2051 Commits
2.3 ... 3.0a

Author SHA1 Message Date
Nicholas Marriott
25ae028695 Add to CHANGES. 2019-12-01 08:53:10 +00:00
nicm
1b0cc4503e REG_STARTEND is not portable, but it turns out we don't actually need
it. From Evan Green, GitHub issue 1982.
2019-12-01 08:52:47 +00:00
Nicholas Marriott
a52fe9cf7f Add to CHANGES. 2019-12-01 08:50:45 +00:00
nicm
48897fbc44 Fix respawn-pane/window if default-command is set, reported by Janos Barbero. 2019-11-29 17:21:32 +00:00
nicm
ad98fad9a3 Do not crash when a format doesn't exist, reported by Thomas Sattler. 2019-11-28 22:23:40 +00:00
nicm
640149337f Missing after-kill-pane option. 2019-11-28 12:22:32 +00:00
Nicholas Marriott
7a30e6b941 Merge branch '3.0-rc' into 3.0a-rc 2019-11-27 20:55:19 +00:00
Nicholas Marriott
0134574a67 3.0a. 2019-11-27 20:49:59 +00:00
Nicholas Marriott
c942f11ba8 Use a malloc'd buffer for lsk since commands can be very long, from Gregory Pakosz. 2019-11-27 20:48:30 +00:00
nicm
5afe7eb850 Do not lazily use BUFSIZ for "I don't care what size" when building
strings because it is only guaranteed to be 256 bytes and even the
default 1024 is not always enough. Reported by Gregory Pakosz.
2019-11-27 20:48:03 +00:00
nicm
b2fd161b07 Do not crash trying to fix layout size if only one cell, from Azat Khuzhin. 2019-11-27 20:47:27 +00:00
Nicholas Marriott
bbcb199174 3.0 version. 2019-11-26 13:16:51 +00:00
nicm
47c0405b33 Some old tmux versions can sometimes generate layout strings which have
the incorrect size for the top cell. Previously tmux didn't care but now
that panes can be partly hidden, the size matters and is checked more
strictly. So add some code to fix up the most common problem and a
sanity check to reject layouts with any other size problems. Reported by
Aleksandrs Ledovskis in GitHub issue 1930.
2019-11-26 13:14:00 +00:00
nicm
f0712a7569 Do not set uninitialized signal mask when creating an empty pane. 2019-09-25 15:56:53 +01:00
nicm
9d1cecea8e Up and Down are already used, use < and > instead. 2019-09-25 15:56:39 +01:00
nicm
e6995196f2 Change menu key bindings to Up and Down and also close it on any mouse
press if opened by key.
2019-09-25 15:56:30 +01:00
nicm
a74e37d32d Mouse formats don't work in copy mode so don't try to use them. 2019-09-25 15:54:52 +01:00
nicm
6f8f4bb206 Make select-pane -P set window-active-style also to match previous
behaviour, reported by Thomas Sattler.
2019-09-24 12:20:25 +01:00
Nicholas Marriott
c739772436 3.0-rc5. 2019-09-16 09:01:56 +01:00
Nicholas Marriott
f27cac585c Add to CHANGES. 2019-09-16 09:00:56 +01:00
nicm
846d57e1b8 Make client exit if pane where input is going is closed. 2019-09-16 09:00:08 +01:00
Nicholas Marriott
54670d898f Missing headers from compat/asprintf.c, from cyyever at outlook dot com. 2019-09-16 08:59:57 +01:00
nicm
c45b255a88 It is not longer necessary to double-escape ; in %%%, problem reported
by Theo Buehler.
2019-09-16 08:59:49 +01:00
nicm
5e4f371408 Fix swap-window -d to work as intended, GitHub issue 1879 from Sam Stuewe. 2019-09-16 08:59:36 +01:00
nicm
7e4439beb7 Remove check for same size - size has already been changed so this
breaks reflow.
2019-09-16 08:58:35 +01:00
nicm
79f09b4d85 Add support for the SD (scroll down) escape sequence, GitHub issue 1861. 2019-08-26 17:28:24 +01:00
nicm
e85ea9f67d grid_view_delete_cells does need to clear, GitHub issue 1871. 2019-08-16 19:34:29 +01:00
nicm
26f2740110 xterm 348 now disables margins when resized, so send DECLRMM again. 2019-08-01 18:52:33 +01:00
Nicholas Marriott
b8b865fb17 Bump 3.0-rc up to master. 2019-07-29 10:53:04 +01:00
Nicholas Marriott
da552eb73b Merge branch 'master' into 3.0-rc 2019-07-29 10:51:30 +01:00
Thomas Adam
b90a9fcd13 Merge branch 'obsd-master' 2019-07-26 23:02:27 +01:00
Nicholas Marriott
e19622b8db Add to CHANGES. 2019-07-26 21:22:53 +01:00
nicm
8f40f791d9 Change "lost server" message to "server exited unexpectedly", from Neal
McBurnett in GitHub issue 1857.
2019-07-26 20:08:40 +00:00
Thomas Adam
bb9a123ddd Merge branch 'obsd-master' 2019-07-24 23:02:30 +01:00
nicm
90dba3ec66 Mark pane status line jobs with FORMAT_STATUS also so it redraws when
they finish, GitHub issue 1852.
2019-07-24 21:16:17 +00:00
Thomas Adam
47712fc113 Merge branch 'obsd-master' 2019-07-19 09:02:26 +01:00
nicm
bf6d1aeaa4 Add a few vi(1) key aliases, from D Ben Knoble. 2019-07-19 07:20:51 +00:00
nicm
df7b5292ab More man page fixes from lacygoill at lacygoill dot me, GitHub issue
1805.
2019-07-19 07:18:03 +00:00
Thomas Adam
7e7c8faa34 Merge branch 'obsd-master' 2019-07-17 21:02:26 +01:00
nicm
f6a9f6b4ad Use the right client for if -b. 2019-07-17 17:49:23 +00:00
nicm
9e7774bb96 Clear overlay on normal key press. 2019-07-17 17:46:51 +00:00
Nicholas Marriott
7c78ebce45 cc, make, libevent, ncurses are dependencies for all builds so no need to list
them for VCS build.
2019-07-17 08:57:22 +01:00
Nicholas Marriott
80b82c8d14 Mention dependencies earlier. 2019-07-17 08:56:10 +01:00
Thomas Adam
8e33cc61b1 Merge branch 'obsd-master' 2019-07-16 17:02:25 +01:00
nicm
99852f8401 Fix check for wrapping when redrawing entire lines, GitHub issue 1836. 2019-07-16 14:11:52 +00:00
Thomas Adam
b749a39cdb Merge branch 'obsd-master' 2019-07-16 13:02:24 +01:00
nicm
b89f2f28bb Fix grid clear code to correctly clear with the default background
colour rather than ending up with the used count higher than the total
size, GitHub issue 1829.
2019-07-16 10:30:56 +00:00
Thomas Adam
a786a59176 Merge branch 'obsd-master' 2019-07-15 21:02:26 +01:00
nicm
eac055bfaf Simplify code to work out if an extra line is needed in the cell. 2019-07-15 18:43:32 +00:00
nicm
6ceeceab7a Make layout_fix_offsets take a window like layout_fix_panes. 2019-07-15 18:25:07 +00:00
Thomas Adam
c9216493cf Merge branch 'obsd-master' 2019-07-10 17:02:25 +01:00
nicm
91b6145499 The command item changes so can't keep getting the target out of it, need to use
the one from the first item. Fixes crash reported by M Kelly.
2019-07-10 14:33:24 +00:00
Thomas Adam
9cbbdb90bf Merge branch 'obsd-master' 2019-07-10 13:02:26 +01:00
nicm
f4d858e7a0 Add -F to refresh-client to specify flags for control clients - one flag
at the moment, no-output which turns off forwarding pane output. From
Thomas Adam. GitHub issue 1834.
2019-07-10 11:20:10 +00:00
Thomas Adam
98ef369b27 Merge branch 'obsd-master' 2019-07-09 17:02:26 +01:00
nicm
fc2016dbb6 Add a -H flag to send-keys to send literal keys given as hex numbers
(needed for control clients to send mouse sequences). Also add some
format flags for UTF-8 and SGR mouse mode. Requested by Bradley Smith in
GitHub issues 1832 and 1833.
2019-07-09 14:03:12 +00:00
Thomas Adam
177599efb7 Merge branch 'obsd-master' 2019-07-09 15:02:25 +01:00
nicm
ad11d49d64 Do not leak empty lines, GitHub issue 1824. 2019-07-09 13:19:36 +00:00
nicm
b74b8be680 Add j and k for navigation in menus, GitHub issue 1828. 2019-07-09 12:44:47 +00:00
Thomas Adam
ab244cc7ad Merge branch 'obsd-master' 2019-07-08 23:02:26 +01:00
nicm
a4be028b76 Clear search marks before resize, GitHub issue 1823. 2019-07-08 20:29:11 +00:00
Thomas Adam
29b2d07b6b Merge branch 'obsd-master' 2019-07-08 15:02:25 +01:00
nicm
cbe781203f Use the clear history function for the 3J sequence rather than doing it manually. 2019-07-08 11:38:14 +00:00
Thomas Adam
3a4cf62aa9 Merge branch 'obsd-master' 2019-07-06 23:02:26 +01:00
nicm
ddf53d6e4e Correctly adjust mouse position if the status line is at the top and
more than one line. GitHub issue 1822.
2019-07-06 20:56:34 +00:00
nicm
3635b3cd6c Correctly clear underscore colour in grid_get_cell1, also fix struct
grid_cell to avoid padding. Fixes increased memory use reported by Suraj
N Kurapati.
2019-07-06 20:37:29 +00:00
Thomas Adam
bc112a8c89 Merge branch 'obsd-master' 2019-07-05 11:02:26 +01:00
nicm
55c694a467 Do not use uninitialized buffer name. 2019-07-05 07:52:27 +00:00
Thomas Adam
be5af704ad Merge branch 'obsd-master' 2019-07-02 23:02:26 +01:00
nicm
6a489fa7f6 Command prompt key presses need to avoid the command queue, GitHub issue
1817. Also a tmux.1 fix from jmc.
2019-07-02 20:09:19 +00:00
Thomas Adam
b9fbf02ad5 Merge branch 'obsd-master' 2019-07-01 09:02:25 +01:00
nicm
2da050413c Add a "fill" style attribute to clear the entire format drawing area in
a colour, GitHub issue 1815.
2019-07-01 06:56:00 +00:00
Thomas Adam
abcd4bd246 Merge branch 'obsd-master' 2019-06-30 21:02:26 +01:00
nicm
cf30e0f935 Do not double free window if pane fails to start. 2019-06-30 19:21:53 +00:00
Thomas Adam
68c2fc6824 Merge branch 'obsd-master' 2019-06-28 17:02:26 +01:00
deraadt
4ff7bc3eb3 When system calls indicate an error they return -1, not some arbitrary
value < 0.  errno is only updated in this case.  Change all (most?)
callers of syscalls to follow this better, and let's see if this strictness
helps us in the future.
2019-06-28 13:35:05 +00:00
Thomas Adam
b6b4f86cfc Merge branch 'obsd-master' 2019-06-28 09:02:24 +01:00
deraadt
6ce38b7395 asprintf returns -1, not an arbitrary value < 0. Also upon error the
(very sloppy specification) leaves an undefined value in *ret, so it is
wrong to inspect it, the error condition is enough.
discussed a little with nicm, and then much more with millert until we
were exasperated
2019-06-28 05:44:09 +00:00
Thomas Adam
a07df21e79 Merge branch 'obsd-master' 2019-06-27 21:02:25 +01:00
jmc
b434692db2 minor eol issues; 2019-06-27 17:29:16 +00:00
Thomas Adam
e483ce138f Merge branch 'obsd-master' 2019-06-27 17:02:26 +01:00
nicm
dae2868d12 Add support for underscore colours with Setulc capability, mostly from
Kai Moschcau.
2019-06-27 15:17:41 +00:00
nicm
5a501a8ae2 Pass keys that aren't 0-9 on to normal key processing when display-panes
is active (restores previous behaviour).
2019-06-27 15:49:43 +01:00
Thomas Adam
c4a9299956 Merge branch 'obsd-master' 2019-06-26 21:02:26 +01:00
nicm
3a6d90adad Fix a typo in window_pane_find_down (w not wp) and a missing PANE_STATUS_TOP. 2019-06-26 18:44:22 +00:00
nicm
87ea14328c Pass keys that aren't 0-9 on to normal key processing when display-panes
is active (restores previous behaviour).
2019-06-26 18:28:31 +00:00
Thomas Adam
f797ac9ff6 Merge branch 'obsd-master' 2019-06-26 15:02:26 +01:00
nicm
c599ad63f8 Log window and pane resizes. 2019-06-26 13:05:24 +00:00
nicm
80d76612b8 Fix some comments (top/bottom not left/right). 2019-06-26 13:05:06 +00:00
nicm
d83f356218 Add #define for the pane status line option position numbers. 2019-06-26 13:03:47 +00:00
Thomas Adam
a1d4bf20f7 Merge branch 'obsd-master' 2019-06-24 13:02:26 +01:00
nicm
20b938bcb1 Expand arguments to C and s format modifiers (matches m which already expands). 2019-06-24 10:04:29 +00:00
Thomas Adam
c14b0d7c00 Merge branch 'obsd-master' 2019-06-24 11:02:26 +01:00
nicm
bdab595095 Trim trailing spaces when matching. 2019-06-24 08:20:02 +00:00
Thomas Adam
50c4c5917d Merge branch 'obsd-master' 2019-06-23 13:02:26 +01:00
nicm
f1100f97f7 Do not always set scope for panes because the window check might fail,
GitHub issue 1810.
2019-06-23 10:00:29 +00:00
Thomas Adam
69a2f73449 Merge branch 'obsd-master' 2019-06-21 09:02:25 +01:00
nicm
e3c2772d2f Man page fixes from lacygoill at lacygoill dot me. 2019-06-21 07:11:01 +00:00
Thomas Adam
70775b3c28 Merge branch 'obsd-master' 2019-06-20 23:02:28 +01:00
nicm
1d8e545bc1 Add -r to find-window for regex instead of fnmatch. 2019-06-20 20:31:04 +00:00
Thomas Adam
c4a92e5799 Merge branch 'obsd-master' 2019-06-20 21:02:27 +01:00
nicm
97a317a656 Need to always check focus even if not current window. 2019-06-20 19:29:38 +00:00
nicm
cb5e681ef6 FIx return of options_scope_from_name on error. 2019-06-20 18:13:04 +00:00
Thomas Adam
5aae58295e Merge branch 'obsd-master' 2019-06-20 19:02:27 +01:00
Thomas Adam
4a44ae06bf Merge branch 'obsd-master' 2019-06-20 17:02:26 +01:00
nicm
f4e835754c Fix how regex substitution works with empty matches. 2019-06-20 15:40:14 +00:00
Thomas Adam
f8ad72b2ee Merge branch 'obsd-master' 2019-06-20 15:02:26 +01:00
nicm
fc1df91e03 allow-rename and alternate-screen can be pane options. 2019-06-20 13:40:22 +00:00
nicm
c1573727f0 Still need to walk the options tree for user options. 2019-06-20 13:39:17 +00:00
Nicholas Marriott
a0e2c1b4ca Add to CHANGES. 2019-06-20 13:08:22 +01:00
nicm
5f92f92908 Add a per-pane option set. Pane options inherit from window options (so
there should be no change to existing behaviour) and are set and shown
with set-option -p and show-options -p.

Change remain-on-exit and window-style/window-active-style to be pane
options (some others will be changed later).

This makes select-pane -P and -g unnecessary so no longer document them
(they still work) and no longer document set-window-option and
show-window-options in favour of set-option -w and show-options -w.
2019-06-20 11:59:59 +00:00
Thomas Adam
adca856806 Merge branch 'obsd-master' 2019-06-20 11:02:28 +01:00
Thomas Adam
03945276f7 Merge branch 'obsd-master' 2019-06-20 09:02:26 +01:00
nicm
c1ede507d9 Add a helper function to work out option table from name. 2019-06-20 07:41:29 +00:00
nicm
cd1fc42df6 Add a -A flag to show-options to show parent options as well. 2019-06-20 07:10:56 +00:00
nicm
ae541287d3 Expand command formats in %if and move the config file loading later (to
when the first client has identified) so all the client formats are
available, fixes problems reported by Thomas Sattler.
2019-06-20 06:51:36 +00:00
Nicholas Marriott
b3ca410bc3 Use KERN_PROC_CWD on NetBSD, from Leonardo Taccari. 2019-06-20 06:57:37 +01:00
Nicholas Marriott
ec151b79ec Merge branch '3.0-rc' 2019-06-18 19:43:20 +01:00
nicm
797042584e Handle comments more correctly inside {}, from Avi Halachmi. 2019-06-18 19:43:13 +01:00
Nicholas Marriott
df07723e20 Add a config. 2019-06-18 19:42:52 +01:00
Thomas Adam
ee9bc355f5 Merge branch 'obsd-master' 2019-06-18 13:02:28 +01:00
nicm
250fdd08be Handle comments more correctly inside {}, from Avi Halachmi. 2019-06-18 11:17:40 +00:00
nicm
9272fe36e2 Add a cmdq_continue function rather than twiddling the flag directly. 2019-06-18 11:08:42 +00:00
Thomas Adam
5895f1d9f7 Merge branch 'obsd-master' 2019-06-15 09:02:26 +01:00
Nicholas Marriott
fadbf497a4 Merge branch '3.0-rc' 2019-06-15 07:45:58 +01:00
Nicholas Marriott
748633c887 Remove a stray abort. 2019-06-15 07:45:41 +01:00
Nicholas Marriott
d53c2d0ebe Merge branch '3.0-rc' 2019-06-15 07:44:58 +01:00
Nicholas Marriott
08f55414e1 Remove cmd-list.c line in master. 2019-06-15 07:42:49 +01:00
Nicholas Marriott
7a4a286ea2 Merge branch '3.0-rc' 2019-06-15 07:38:01 +01:00
nicm
9ae658983c Do not loop forever if a menu item contains invisible characters,
reported by Thomas Sattler.
2019-06-15 07:37:44 +01:00
nicm
03da0ced46 Use the right format modifier when comparing, and remove a couple of
unused variables.
2019-06-15 06:33:48 +00:00
Thomas Adam
539a6e7fa0 Merge branch 'obsd-master' 2019-06-14 19:02:26 +01:00
nicm
c95cd9ed5e Do not loop forever if a menu item contains invisible characters,
reported by Thomas Sattler.
2019-06-14 15:35:58 +00:00
Nicholas Marriott
c22470bd14 3.0-rc3. 2019-06-14 16:17:34 +01:00
Nicholas Marriott
4c28ed4e4e Merge branch '3.0-rc' 2019-06-14 16:10:38 +01:00
Nicholas Marriott
31cb95893e #{ is no longer special. 2019-06-14 16:10:27 +01:00
Nicholas Marriott
ae83a5b010 Add to CHANGES. 2019-06-14 16:09:49 +01:00
Nicholas Marriott
29b70e2757 Merge branch '3.0-rc' 2019-06-14 16:06:20 +01:00
nicm
52b8274285 Do not crash if the environment variable is present but empty. 2019-06-14 16:06:12 +01:00
Nicholas Marriott
dcb2bb33a2 Merge branch '3.0-rc' 2019-06-14 16:05:26 +01:00
nicm
a924694820 Use the right client when working out where to save or load the buffer,
reported by kn@.
2019-06-14 16:04:57 +01:00
nicm
0a94dbe051 A couple of minor parser changes around conditions: 1) only treat #{
specially after a condition, otherwise as a comment (which is more as
most people expect) 2) allow formats to be quoted after a condition.
2019-06-14 16:04:52 +01:00
Nicholas Marriott
8da756c4f0 Restore missing functions. 2019-06-14 16:02:34 +01:00
Nicholas Marriott
7bb8ab1c0e Add a bit to {}. 2019-06-14 15:54:36 +01:00
Thomas Adam
5e9757b30b Merge branch 'obsd-master' 2019-06-14 15:51:09 +01:00
nicm
d1d3bbb458 Show filename with -v for source-file. 2019-06-14 13:34:45 +00:00
nicm
45203582ff A couple of minor parser changes around conditions: 1) only treat #{
specially after a condition, otherwise as a comment (which is more as
most people expect) 2) allow formats to be quoted after a condition.
2019-06-14 12:04:11 +00:00
Nicholas Marriott
ebc9dcb3bb Add a bit to {}. 2019-06-14 12:40:35 +01:00
Nicholas Marriott
4bbf941436 Merge branch '3.0-rc' 2019-06-14 10:34:05 +01:00
Nicholas Marriott
f31847db62 Improve description of #{. 2019-06-14 10:33:55 +01:00
nicm
f35f15b107 Use the right client when working out where to save or load the buffer,
reported by kn@.
2019-06-13 21:44:13 +00:00
nicm
eef11b64e1 Do not crash if the environment variable is present but empty. 2019-06-13 21:24:09 +00:00
jmc
b8a9c740bb tweak previous; 2019-06-13 21:04:21 +00:00
nicm
26b9a8e49b Set the cursor x at the same time as changing the y or the end of line
marker may not be redrawn.
2019-06-13 20:38:05 +00:00
nicm
3e72e98e3b Add regular expression support for the format search, match and
substitute modifiers.
2019-06-13 19:46:00 +00:00
Thomas Adam
d5902eeae9 Merge branch 'obsd-master' 2019-06-12 11:02:25 +01:00
nicm
7e6a26cc9d Do not use $TMUX to find the session because for windows in multiple
sessions it is wrong as often as it is right, and for windows in one
session it is pointless. Instead check TMUX_PANE to find the pane and
look for the MRU session as usual. GitHub issue 1793.
2019-06-12 09:10:29 +00:00
nicm
b12df01861 Pass target on to new commands with if -F. 2019-06-12 08:47:07 +00:00
nicm
9d42bd328c Do not always resize the window back to its original size after applying
a layout, let the normal window resize process do it. This means windows
are not resized at all if window-size is manual, and are not resized
multiple times if later attached to a different size terminal.
2019-06-12 08:08:33 +00:00
nicm
e337c1ba7d Do not try to parse command when unsetting, GitHub issue 1788. 2019-06-11 15:51:30 +01:00
Thomas Adam
057c04e32a Merge branch 'obsd-master' 2019-06-11 15:02:26 +01:00
Nicholas Marriott
8e971f187a Update README.md 2019-06-11 14:27:40 +01:00
Nicholas Marriott
e8814a7e93 Add to CHANGES. 2019-06-11 14:23:47 +01:00
nicm
1a9f9c09b4 Do not resize panes unless they are in an attached, active window. From
Morten M Neergaard in GitHub issue 1782.
2019-06-11 13:09:00 +00:00
Thomas Adam
d9ad461b5e Merge branch 'obsd-master' 2019-06-09 09:02:26 +01:00
nicm
915097d312 Exiting alternate screen mode should restore cursor position and
attributes even if already outside alternate screen mode. GitHub issue
1789.
2019-06-09 06:50:24 +00:00
Thomas Adam
181841fb67 Merge branch 'obsd-master' 2019-06-09 01:02:26 +01:00
nicm
43796bf131 Do not try to parse command when unsetting, GitHub issue 1788. 2019-06-08 21:48:29 +00:00
Thomas Adam
e13c1e5320 Merge branch 'obsd-master' 2019-06-07 23:02:26 +01:00
nicm
e37f34facc Do not load the config file if the server is exiting because it failed
to start, otherwise commands like lsk which start the server again can
end up looping infinitely. Also make the first client exit
correctly. Problem reported by Wael M Nasreddine.
2019-06-07 20:09:17 +00:00
Thomas Adam
c91680822d Merge branch 'obsd-master' 2019-06-05 23:02:26 +01:00
Nicholas Marriott
37bb993f53 Merge branch '3.0-rc' 2019-06-05 21:06:30 +01:00
nicm
db5a7c1740 Need to increment the argument to skip the prefix earlier, fixes
repeated incremental search in copy mode, reported by Kaushal Modi in
GitHub issue 1780.
2019-06-05 21:06:06 +01:00
Thomas Adam
1ec3fb5f30 Merge branch 'obsd-master' 2019-06-05 21:02:26 +01:00
nicm
8f40796f05 Add a -v flag to source-file to show the commands and line numbers. 2019-06-05 20:00:53 +00:00
nicm
09e90c1645 Need to increment the argument to skip the prefix earlier, fixes
repeated incremental search in copy mode, reported by Kaushal Modi in
GitHub issue 1780.
2019-06-05 19:00:36 +00:00
Nicholas Marriott
f274b1b9d7 Merge branch '3.0-rc' 2019-06-05 15:13:56 +01:00
Nicholas Marriott
53914e50b9 RC2. 2019-06-05 15:09:42 +01:00
Nicholas Marriott
e252984993 If only one of -x or -y is given, use the calculated size for the
other. Also fix some warnings. Pointed out by Ben Boeckel.
2019-06-05 06:44:08 +01:00
Thomas Adam
d3f0c72e20 Merge branch 'obsd-master' 2019-06-03 21:02:26 +01:00
nicm
4ca1de1b8b Add new-session -X and attach-session -x to send SIGHUP to parent when
detaching (like detach-client -P). From Colin Watson in GitHub issue
1773.
2019-06-03 18:28:37 +00:00
nicm
17bc11bd15 yacc(1) copies its union so it is not a good place to store
TAILQ_HEADs. Allocate them instead. Found from a problem reported by
sthen@.
2019-06-02 10:52:32 +01:00
Thomas Adam
f6933e43c2 Merge branch 'obsd-master' 2019-06-02 09:02:27 +01:00
nicm
900238a306 yacc(1) copies its union so it is not a good place to store
TAILQ_HEADs. Allocate them instead. Found from a problem reported by
sthen@.
2019-06-02 07:10:15 +00:00
Thomas Adam
027a7ac829 Merge branch 'obsd-master' 2019-06-01 19:02:26 +01:00
nicm
2c6c3a1d27 If only one of -x or -y is given, use the calculated size for the
other. Pointed out by Ben Boeckel.
2019-06-01 16:21:37 +00:00
Thomas Adam
8382ae65b7 Merge branch 'obsd-master' 2019-06-01 09:02:27 +01:00
Nicholas Marriott
ec690208a3 Move link. 2019-06-01 08:07:22 +01:00
Nicholas Marriott
b28b8312f2 Mention CHANGES. 2019-06-01 08:05:55 +01:00
Nicholas Marriott
c2d79add31 Should be caps. 2019-06-01 07:28:31 +01:00
Nicholas Marriott
feff55b92f Try this instead. 2019-06-01 07:26:39 +01:00
Nicholas Marriott
3d29b97768 Link to file. 2019-06-01 07:24:57 +01:00
nicm
39ea8a2787 Need stdlib.h, from Ben Boeckel. 2019-06-01 06:20:22 +00:00
Thomas Adam
480cdedcac Merge branch 'obsd-master' 2019-06-01 01:02:25 +01:00
Nicholas Marriott
88ee5a1a00 Add a crashing config. 2019-05-31 22:50:30 +01:00
nicm
2c5f3074bc Fix warnings, from Ben Boeckel. 2019-05-31 21:41:17 +00:00
Nicholas Marriott
9d2ef8bf0d Merge branch '3.0-rc' 2019-05-31 15:18:56 +01:00
nicm
1a3a973bd0 Allow % strings that are all numbers or %s, and fix a double free. Both
reported by George Nachman, GitHub issues 1765 and 1766.
2019-05-31 15:18:25 +01:00
Thomas Adam
adf9e77702 Merge branch 'obsd-master' 2019-05-31 15:02:27 +01:00
nicm
82e47403c6 Allow % strings that are all numbers or %s, and fix a double free. Both
reported by George Nachman, GitHub issues 1765 and 1766.
2019-05-31 11:34:09 +00:00
Thomas Adam
41b8bb4eef Merge branch 'obsd-master' 2019-05-30 23:02:27 +01:00
nicm
b26523c26d Remove a leftover abort and some fixes from cppcheck. 2019-05-30 20:54:03 +00:00
Nicholas Marriott
200a1c62c6 Merge branch '3.0-rc' 2019-05-30 13:12:50 +01:00
nicm
e4eec92852 No longer need to reduce line number by one. 2019-05-30 13:12:35 +01:00
Thomas Adam
2df757521a Merge branch 'obsd-master' 2019-05-30 13:02:26 +01:00
nicm
8fb796b5b3 No longer need to reduce line number by one. 2019-05-30 10:04:33 +00:00
Thomas Adam
82b25a9d62 Merge branch 'obsd-master' 2019-05-30 11:02:27 +01:00
nicm
89d2c7eb26 I had hoped that non-xenl terminals had died out, at least in fairly
modern OSs, but no - DragonFly BSD's console returns to haunt us. Fix it
at least somewhat. GitHub issue 1763.
2019-05-30 07:42:41 +00:00
Nicholas Marriott
026450c1a8 Add test for xenl terminals. 2019-05-30 07:52:24 +01:00
Nicholas Marriott
c5e2532b67 Merge branch '3.0-rc' 2019-05-29 23:04:28 +01:00
nicm
75d112c484 The line number needs to be updated only after the \n is processed by
the parser, so store a flag and update it next time around. Also each
new line needs its own shared data.
2019-05-29 23:04:22 +01:00
Thomas Adam
414208aab1 Merge branch 'obsd-master' 2019-05-29 23:02:25 +01:00
nicm
7dced37673 Use VIS_CSTYLE for the arguments and add the missing escapes it can
generate to the parser.
2019-05-29 20:05:14 +00:00
Nicholas Marriott
95d68fcba1 Merge branch '3.0-rc' 2019-05-29 20:43:29 +01:00
Nicholas Marriott
a05c3a7aa6 Add command order test. 2019-05-29 20:43:11 +01:00
nicm
c17edd594e The line number needs to be updated only after the \n is processed by
the parser, so store a flag and update it next time around. Also each
new line needs its own shared data.
2019-05-29 19:34:42 +00:00
Nicholas Marriott
47795d1695 Update .travis.yml from master. 2019-05-29 14:40:41 +01:00
Nicholas Marriott
2ce8e0110c Don't even need this? 2019-05-29 14:32:49 +01:00
Nicholas Marriott
4425c1e1b3 Tweak again. 2019-05-29 14:24:09 +01:00
Nicholas Marriott
409d52ed41 Try OS X. 2019-05-29 14:19:37 +01:00
Thomas Adam
e90b5dcea3 Merge branch 'obsd-master' 2019-05-29 13:02:35 +01:00
Nicholas Marriott
ffcc60211d Merge branch '3.0-rc' 2019-05-29 12:13:55 +01:00
Nicholas Marriott
7cdb1cfc8d as -> and. 2019-05-29 12:13:46 +01:00
Nicholas Marriott
480ba99a16 Merge branch '3.0-rc' 2019-05-29 12:07:05 +01:00
Nicholas Marriott
8827b7f9a6 Tweak {} text. 2019-05-29 11:25:07 +01:00
nicm
a4424fbebf Support \ooo escapes, from Avi Halachmi. 2019-05-29 10:08:36 +00:00
Nicholas Marriott
eefbbfde77 Merge branch '3.0-rc' 2019-05-28 21:05:00 +01:00
nicm
7eeb479705 Do not read past the end of the argument string if it is empty. 2019-05-28 21:04:41 +01:00
nicm
8d137233a9 Redraw status line if size changes, GitHub issue 1762. Also fix length
of target buffer when pasting into status line.
2019-05-28 21:04:35 +01:00
Thomas Adam
c96957583f Merge branch 'obsd-master' 2019-05-28 21:02:28 +01:00
nicm
580cd16f4c Redraw status line if size changes, GitHub issue 1762. Also fix length
of target buffer when pasting into status line.
2019-05-28 18:53:36 +00:00
nicm
4382538e4b Do not read past the end of the argument string if it is empty. 2019-05-28 18:30:30 +00:00
Nicholas Marriott
e7a530fe4c Next will be 3.1. 2019-05-28 15:48:31 +01:00
Nicholas Marriott
05d07413ff 3.0-rc. 2019-05-28 15:46:17 +01:00
Thomas Adam
b8360504f3 Merge branch 'obsd-master' 2019-05-28 15:02:26 +01:00
Nicholas Marriott
a062650d4b Tweak menu option. 2019-05-28 14:49:50 +01:00
Nicholas Marriott
f012db9be9 Add regress for conf files. 2019-05-28 13:21:19 +01:00
nicm
299d4f3aaa Exit 1 correctly if source-file fails. 2019-05-28 12:20:28 +00:00
Thomas Adam
eba6cf61c9 Merge branch 'obsd-master' 2019-05-28 13:02:27 +01:00
nicm
0ec410689c Allow source-file to take multiple arguments. 2019-05-28 11:46:30 +00:00
nicm
e0fd295054 Change the default right click pane to open the menu if not in a mode
and no application mouse.
2019-05-28 10:27:11 +00:00
nicm
99a8469ee4 Add key bindings to open the window and pane menus (C-m and M-m for now). 2019-05-28 10:05:24 +00:00
nicm
12255411f2 Allow menu items to be disabled by putting a - at the start of their
name, rather than just including #[dim] which still allowed them to be
chosen.
2019-05-28 09:50:54 +00:00
Thomas Adam
c0116b2c5b Merge branch 'obsd-master' 2019-05-28 09:02:26 +01:00
nicm
799a154b91 Change display-menu from taking a single string to a set of arguments,
which is much easier to work with. Based on a diff from Avi Halachmi.
2019-05-28 07:18:42 +00:00
Thomas Adam
793f4d89d6 Merge branch 'obsd-master' 2019-05-27 19:02:25 +01:00
nicm
90cd045cf3 Clarify newlines inside {} a little. 2019-05-27 16:22:32 +00:00
nicm
94f6488f0e Go less crazy with horizontal separators on default menus. 2019-05-27 15:29:46 +00:00
Thomas Adam
d4bf4bd7c7 Merge branch 'obsd-master' 2019-05-27 15:02:28 +01:00
Nicholas Marriott
522d1bd309 Add. 2019-05-27 14:39:44 +01:00
Nicholas Marriott
a21de4c483 Mention <><=>=. 2019-05-27 14:39:06 +01:00
Nicholas Marriott
714311a696 Add {}. 2019-05-27 14:37:47 +01:00
Nicholas Marriott
9f0904ce6f Remove unused fparseln compat code. 2019-05-27 14:28:05 +01:00
nicm
ae3eba6e08 Fix crash when killing the current window, reported by Jesus Rafael
Sanchez in GitHub issue 1760.
2019-05-27 12:48:52 +00:00
nicm
6b332127ca Add an additional {} syntax for defining strings in the configuration
file, making it much tidier to define commands that contain other tmux
or shell commands (like if-shell). Also tweak bind-key to expect a
string if it is only given one argument, so {} can be used with it as
well. From Avi Halachmi.
2019-05-27 12:16:27 +00:00
Thomas Adam
bd40d704e2 Merge branch 'obsd-master' 2019-05-27 09:02:26 +01:00
nicm
65e5e14561 Fix the intended ordering of items in buffer mode - it should not always
be tag 0 when the tree is empty. GitHub issue 1759.
2019-05-27 06:50:04 +00:00
Thomas Adam
103e44d936 Merge branch 'obsd-master' 2019-05-26 21:02:26 +01:00
nicm
097973e3d5 Add keys for new menu items. 2019-05-26 18:43:43 +00:00
nicm
5fef946df4 Always redraw overlay if it is on (so status line doesn't redraw over it). 2019-05-26 18:27:52 +00:00
nicm
023c2c5392 Do not accept choice unless mouse has actually moved before. 2019-05-26 18:19:52 +00:00
nicm
e90d4a6021 Add formats for word and line under the mouse and use them to add some
items to the pane menu.
2019-05-26 17:34:45 +00:00
Thomas Adam
2e84d1cf03 Merge branch 'obsd-master' 2019-05-26 15:02:25 +01:00
nicm
6431005169 Add a way to append or prepend to a format if the length has been limited. 2019-05-26 12:02:42 +00:00
Thomas Adam
9beb3eb593 Merge branch 'obsd-master' 2019-05-26 13:02:26 +01:00
nicm
6dee409981 Some other platforms doesn't support fmemopen(3) (not unexpectedly), so
don't use it - since we only use getc/ungetc on the file anyway it is
easy not to.
2019-05-26 10:08:50 +00:00
Thomas Adam
f3fc81b178 Merge branch 'master' of github.com:ThomasAdam/tmux 2019-05-25 18:50:05 +01:00
Thomas Adam
463bd8abb9 Merge branch 'obsd-master' 2019-05-25 18:41:51 +01:00
nicm
a65a6d62d1 Add <, >, <=, >= for formats, GitHub issue 1747. 2019-05-25 16:51:10 +00:00
nicm
207789dc2d Client name can actually be NULL, so use address in that case. 2019-05-25 10:46:55 +00:00
nicm
d7586d3d65 Use client name when logging command queue. 2019-05-25 10:44:09 +00:00
nicm
f8d3d247d8 Merge cmd_list_parse into cmd-parse.y so it can use the new alias
processing code.
2019-05-25 07:18:20 +00:00
nicm
6b0fa14470 Fix error handling in if-shell. 2019-05-25 07:15:53 +00:00
Nicholas Marriott
a69211aff5 Fix up regress test. 2019-05-25 08:09:23 +01:00
nicm
930245d7ff Make cmd_log_argv take a printf-like format for the prefix. 2019-05-25 06:58:10 +00:00
espie
0dc8b7d5d8 unbreak build, okay nicm@ 2019-05-23 21:36:42 +00:00
Thomas Adam
19a3a9ee20 Merge branch 'obsd-master' 2019-05-23 21:02:30 +01:00
nicm
f3e01ecc42 Fix line numbers - commands are added after the line ends so they need to
get line - 1.
2019-05-23 18:39:00 +00:00
nicm
6c260af56d Use the same argument escaping code for options as well. 2019-05-23 18:33:53 +00:00
Nicholas Marriott
e817821104 Mention \. 2019-05-23 19:27:41 +01:00
nicm
f006116bac Environment variables can start with { also. 2019-05-23 18:22:13 +00:00
Thomas Adam
43431e7e84 Merge branch 'obsd-master' 2019-05-23 17:02:25 +01:00
nicm
eb8b51effc Fix drawing of status-right when it is aligned to the centre, GitHub
issue 1754.
2019-05-23 14:44:33 +00:00
Nicholas Marriott
389cf63cbc Tweak text. 2019-05-23 15:18:20 +01:00
Thomas Adam
2148fe33cd CHANGES: remove note to packagers 2019-05-23 15:16:10 +01:00
Thomas Adam
1a6540fea0 CHANGES: remove note to packagers 2019-05-23 15:15:42 +01:00
nicm
7d702f3cef Don't remove group items for group 0 (no group). 2019-05-23 15:15:42 +01:00
nicm
d0c462f718 Fix length calculation for pasting UTF-8 characters in the status line,
GitHub issue 1753.
2019-05-23 15:15:42 +01:00
Thomas Adam
238d2aa870 CHANGES: mention yacc 2019-05-23 15:12:24 +01:00
Thomas Adam
6bb505eb73 CHANGES: mention yacc 2019-05-23 15:11:25 +01:00
Nicholas Marriott
83b9807370 Remove duplicate. 2019-05-23 15:11:25 +01:00
Nicholas Marriott
3e6e533779 Add yacc(1) bits. 2019-05-23 15:11:25 +01:00
nicm
27bfb56ad5 Break the argument escaping code into a separate function and use it to
escape key bindings in list-keys. Also escape ~ and ; and $ properly.
2019-05-23 14:03:44 +00:00
Thomas Adam
c49f2a0365 Merge branch 'obsd-master' 2019-05-23 15:02:28 +01:00
nicm
3e3eb1dd0f Don't remove group items for group 0 (no group). 2019-05-23 13:08:43 +00:00
nicm
a4fe7e81c8 Fix length calculation for pasting UTF-8 characters in the status line,
GitHub issue 1753.
2019-05-23 12:47:52 +00:00
Nicholas Marriott
4ce26b0393 Remove duplicate. 2019-05-23 13:32:18 +01:00
Thomas Adam
82bf0f4d48 configure.ac: add AC_PROC_YACC 2019-05-23 13:12:03 +01:00
Thomas Adam
8590ee65e6 TRAVIS: add bison to build deps 2019-05-23 13:12:03 +01:00
Thomas Adam
d67b99c7e4 configure.ac: add AC_PROC_YACC 2019-05-23 13:09:34 +01:00
Thomas Adam
092c7bfeb8 TRAVIS: add bison to build deps 2019-05-23 13:06:47 +01:00
Nicholas Marriott
bf2cf33fc6 Add yacc(1) bits. 2019-05-23 13:04:41 +01:00
Thomas Adam
75aeb733f2 Merge branch 'obsd-master' 2019-05-23 13:02:27 +01:00
nicm
723010ba72 Replace the split parser code (cfg.c and cmd-string.c) with a single
parser using yacc(1). This is a major change but is clearer and simpler
and allows some edge cases to be made more consistent, as well as
tidying up how aliases are handled. It will also allow some further
improvements later.

Entirely the same parser is now used for parsing the configuration file
and for string commands. This means that constructs previously only
available in .tmux.conf, such as %if, can now be used in string commands
(for example, those given to if-shell - not commands invoked from the
shell, they are still parsed by the shell itself).

The only syntax change I am aware of is that #{} outside quotes or a
comment is now considered a format and not a comment, so #{ is now a
syntax error (notably, if it is at the start of a line).

This also adds two new sections to the man page documenting the syntax
and outlining how parsing and command execution works.

Thanks to everyone who sent me test configs (they still all parse
without errors - but this doesn't mean they still work as intended!).

Thanks to Avi Halachmi for testing and man page improvements, also to
jmc@ for reviewing the man page changes.
2019-05-23 11:13:30 +00:00
Nicholas Marriott
7ca2e2fe88 Add a config. 2019-05-23 11:57:04 +01:00
Thomas Adam
9d450cc6d0 Merge branch 'obsd-master' 2019-05-22 21:02:28 +01:00
nicm
5571d7a21c Fix crash if window doesn't exist, GitHub issue 1751. 2019-05-22 18:58:31 +00:00
Nicholas Marriott
e353d0cab3 Another config. 2019-05-22 19:49:48 +01:00
Nicholas Marriott
282f7fbd37 Add a test config. 2019-05-22 13:31:20 +01:00
Nicholas Marriott
b68fc7f104 Two more configs. 2019-05-22 07:12:38 +01:00
Nicholas Marriott
54dfe36340 Another. 2019-05-21 17:07:08 +01:00
Thomas Adam
c4f4904f9b More configs 2019-05-21 16:43:34 +01:00
Nicholas Marriott
d769fec8d6 More configs. 2019-05-21 14:41:07 +01:00
Nicholas Marriott
f1ce611345 Add another one. 2019-05-21 11:28:12 +01:00
Thomas Adam
3856116069 Merge branch 'obsd-master' 2019-05-21 09:02:37 +01:00
Nicholas Marriott
afe231c94c Add a few test configs thanks to various people. 2019-05-21 08:02:17 +01:00
nicm
ae4cccb4f1 Fix a couple of Ta from Alphonse Mariya. 2019-05-21 07:01:14 +00:00
Thomas Adam
98ee93bde3 Merge branch 'obsd-master' 2019-05-20 15:02:40 +01:00
nicm
87d82170a6 Fix ordering of source-file with multiple files and add flags to load_cfg. 2019-05-20 13:23:32 +00:00
Thomas Adam
3a7e15511b Merge branch 'obsd-master' 2019-05-20 13:02:36 +01:00
nicm
e128c7fcd8 Replace the various identical error callbacks with a single one in cmd-queue.c. 2019-05-20 11:46:06 +00:00
nicm
8db89f8efb Add a helper to allocate a cmd_list. 2019-05-20 11:34:37 +00:00
Thomas Adam
c271cb9ff8 Merge branch 'obsd-master' 2019-05-20 07:02:36 +01:00
nicm
6e0c663a89 Fix the color space parameter in RGB SGR, from Brad Town. 2019-05-20 05:35:46 +00:00
Thomas Adam
56246c2936 README.md: mention TODO list on the tmux wiki 2019-05-19 13:31:09 +01:00
Thomas Adam
54da493476 Merge branch 'obsd-master' 2019-05-18 23:02:36 +01:00
nicm
82ebd98c5f Move the single command flag (CMD_CONTROL) into the shared flags. 2019-05-18 21:14:10 +00:00
Nicholas Marriott
831c67c2d8 Remove TODO, moving onto website. 2019-05-18 14:44:31 +01:00
Nicholas Marriott
d6f7be6345 Add to CHANGES. 2019-05-18 13:29:38 +01:00
Thomas Adam
eb064e8a62 Merge branch 'obsd-master' 2019-05-17 09:02:36 +01:00
nicm
9b83b1daa6 Change a couple of ACS characters to be more sensible and add a few
missing ones, reported by Ricardo Banffy.
2019-05-17 05:48:25 +00:00
nicm
4acd345c6a Initialize default size variables, from Thomas Adam. 2019-05-17 05:47:31 +00:00
Thomas Adam
d9ac0e7576 Merge branch 'obsd-master' 2019-05-15 22:50:42 +01:00
Nicholas Marriott
dcf0bc2cc9 Mention CONTRIBUTING. 2019-05-15 21:42:43 +01:00
nicm
cf4566b47b Fix dragging when in view mode rather than copy mode, GitHub issue 1740
from Brad Town.
2019-05-15 19:25:53 +00:00
Nicholas Marriott
50e77536fe Less headings. 2019-05-15 20:21:38 +01:00
Nicholas Marriott
cd4e467751 Kill tmux for logs. 2019-05-15 20:21:07 +01:00
Thomas Adam
9228fead48 Merge branch 'obsd-master' 2019-05-14 09:02:28 +01:00
nicm
38b8a198ba Fix sizing of main-vertical and main-horizontal layouts, GitHub issue 1736. 2019-05-14 07:37:50 +00:00
Thomas Adam
1eefbd28e8 Merge branch 'obsd-master' 2019-05-13 23:02:26 +01:00
nicm
1ee944a19d Add support for overline (SGR 53), from Ricardo Banffy. 2019-05-13 20:10:23 +00:00
nicm
1b0512aa7e Always include Lock in the menu. 2019-05-13 20:07:02 +00:00
Thomas Adam
b5b5d35eee Merge branch 'obsd-master' 2019-05-13 11:02:31 +01:00
nicm
c5f660e33a Fix column width for copy mode commands. 2019-05-13 08:56:07 +00:00
Nicholas Marriott
e1e520d741 Clarify a little. 2019-05-13 09:51:51 +01:00
Thomas Adam
699d9d2fac Merge branch 'obsd-master' 2019-05-12 21:02:27 +01:00
nicm
c3c3927c2b Oops, removed too much in last change. 2019-05-12 18:18:30 +00:00
nicm
00f19b7f91 Fix some indentation and dead assignments. 2019-05-12 18:16:33 +00:00
Thomas Adam
42da951edf README.md: avaailable -> available
Correct typo.
2019-05-12 18:37:32 +01:00
Thomas Adam
180bbab1fc Merge branch 'obsd-master' 2019-05-12 11:02:25 +01:00
Nicholas Marriott
69c59c52b6 Spelling error. 2019-05-12 10:06:42 +01:00
Nicholas Marriott
19370631ea Tweak text of menu CHANGES entry. 2019-05-12 10:05:10 +01:00
Nicholas Marriott
99c1853792 Scatter some `. 2019-05-12 10:00:31 +01:00
nicm
a131655235 Add simple menus to tree, client, buffer modes. 2019-05-12 08:58:09 +00:00
Thomas Adam
677bb168a9 Merge branch 'obsd-master' 2019-05-12 09:02:28 +01:00
nicm
c91323e4d6 Remove menu_create_from_items, I thought I would use it for some later
work but I don't need it.
2019-05-12 07:27:08 +00:00
Thomas Adam
50d1d04913 Merge branch 'obsd-master' 2019-05-11 09:02:29 +01:00
Nicholas Marriott
67e2f5869a Mention -vv. 2019-05-11 08:34:08 +01:00
Nicholas Marriott
3a9c199ae7 New ISSUE_TEMPLATE from Nicolas CARPi. 2019-05-11 08:23:14 +01:00
Nicholas Marriott
bd6d0b3101 Formatted README.md, from Nicolas CARPi. 2019-05-11 08:19:14 +01:00
Nicholas Marriott
f1dd65cbdf Another tweak. 2019-05-11 08:09:49 +01:00
Nicholas Marriott
c18d7c5fcb Update CONTRIBUTING.md, mostly from Nicolas CARPi. 2019-05-11 08:07:35 +01:00
Nicholas Marriott
0d64531f66 Tweaks to README, some from me, some from Nicolas CARPi. 2019-05-11 07:55:28 +01:00
Nicholas Marriott
f44dafd224 Add to CHANGES. 2019-05-11 07:43:18 +01:00
nicm
198b0a23a2 Don't use arguments with It and -enum, pointed out by jmc. 2019-05-11 06:40:01 +00:00
nicm
ad27b7decd Do not reduce window height by status line height for control mode
clients, from George Nachman.
2019-05-11 06:34:56 +00:00
Thomas Adam
fc00839adc Update CHANGES 2019-05-10 22:27:33 +01:00
Thomas Adam
aa13bd4016 Merge branch 'obsd-master' 2019-05-10 22:10:38 +01:00
nicm
d62fd78655 Fix a typo in previous (, -> :). 2019-05-10 18:09:51 +00:00
nicm
6dcca5fda4 Add support for simple menus usable with mouse or keyboard. New command
display-menu shows a menu (bound to the mouse on status line by default)
and a couple of extra formats for the default menus.
2019-05-10 18:04:06 +00:00
Thomas Adam
c5f6ea5c0d Merge branch 'obsd-master' 2019-05-10 17:02:27 +01:00
nicm
004a9b52f0 Add a function to draw a simple menu onto a screen. 2019-05-10 14:12:47 +00:00
Thomas Adam
e5f06d2cf6 Merge branch 'obsd-master' 2019-05-09 17:02:25 +01:00
nicm
cb10bfb8ef Save mouse buttons as well as position. 2019-05-09 14:09:32 +00:00
Thomas Adam
2e00d775e4 Merge branch 'obsd-master' 2019-05-09 15:02:26 +01:00
nicm
21d9750450 send-keys also needs to insert key commands in the right order. 2019-05-09 13:12:59 +00:00
Thomas Adam
f431e20f3d Merge branch 'obsd-master' 2019-05-09 11:02:25 +01:00
nicm
3c68e51609 Change swap-window -d to be the other way round (stay with src window),
so it works like swap-pane.
2019-05-09 08:39:09 +00:00
nicm
299b7289ea Add formats to show if pane is the marked pane and if any marked pane is set. 2019-05-09 08:38:13 +00:00
Thomas Adam
4bc45fc95a Merge branch 'obsd-master' 2019-05-08 21:02:25 +01:00
nicm
f9682d2e55 Add a flag to redraw only the overlay, and remove the overlay on resize. 2019-05-08 18:07:12 +00:00
nicm
a384245c5a Adjust how mouse targets are found so they always have a session, window
and pane.
2019-05-08 18:05:03 +00:00
Thomas Adam
b24d7d9c95 Merge branch 'obsd-master' 2019-05-07 23:02:30 +01:00
Thomas Adam
453a62c672 Merge branch 'obsd-master' 2019-05-07 21:02:25 +01:00
nicm
89db309e10 Move around the display-panes identify code to make it a bit more
generic and hide the display-panes specific bits into
cmd-display-panes.c.
2019-05-07 20:01:41 +00:00
nicm
d53d3bce59 Adjust the same bit to adjust the selection for history-top and
history-bottom as for cursor-up and cursor-down. GitHub issue 1723.
2019-05-07 19:46:17 +00:00
Thomas Adam
3439c02e9d Merge branch 'obsd-master' 2019-05-07 17:02:25 +01:00
schwarze
fcd0e3082b Rename the ENVIRONMENT section which was squatting on the standard
manual page section and create a new ENVIRONMENT with the expected
content.  Move some information that was misplaced below the -u
flag into that new section.
Feedback and OK nicm@ jmc@ tb@
2019-05-07 14:01:39 +00:00
Thomas Adam
d9767b8112 Merge branch 'obsd-master' 2019-05-07 13:02:27 +01:00
nicm
85a9c2f52b Treat keys in identify mode (display-panes) specially and handle them
immediately rather than queuing them (the command can block the queue
which means they were not being seen until it finished which was too
late). Reported by denis@ and solene@, ok solene@.
2019-05-07 11:24:03 +00:00
nicm
69440d19b7 Do not use evbuffer_add_buffer because it is destructive and doesn't
work in newer libevent.
2019-05-07 10:25:15 +00:00
Nicholas Marriott
eac30a86d7 -attr -> -style. 2019-05-06 21:57:32 +01:00
Thomas Adam
d4177e954c Merge branch 'obsd-master' 2019-05-03 23:02:28 +01:00
nicm
45ae9a8e35 Fix order of insertion in load_cfg. 2019-05-03 21:21:00 +00:00
nicm
9f75635596 Allow panes to be empty (no command), output can be piped to them with
split-window or display-message -I.
2019-05-03 20:44:24 +00:00
Thomas Adam
4d505574dc Merge branch 'obsd-master' 2019-05-03 21:02:26 +01:00
nicm
e8e4f4ec3e Insert after the right element on queue. 2019-05-03 18:59:58 +00:00
nicm
4097257bef Do not store the mouse position we calculate as the start of a drag back
into the mouse event that later code uses, it has been adjusted and they
should use the original position. GitHub issue 1710.
2019-05-03 18:42:40 +00:00
Thomas Adam
a14512e23e Merge branch 'obsd-master' 2019-05-03 19:02:27 +01:00
nicm
84e4652513 Use the right index for user-keys. 2019-05-03 18:00:19 +00:00
nicm
fc3d85e34b Fix mouse positioning when the pane is not entirely visible. 2019-05-03 16:51:29 +00:00
Nicholas Marriott
43656d4ea7 Sync up some tmux.1 bits. 2019-05-03 17:12:30 +01:00
Thomas Adam
fff85d854e Merge branch 'obsd-master' 2019-05-03 17:04:11 +01:00
nicm
cf6075fb29 Correct ordering when adding after an existing item. 2019-05-03 15:43:01 +00:00
nicm
33298d6df6 Instead of processing keys all together, put them up on the client
command queue so they are ordered correctly with the commands that they
execute.
2019-05-03 14:51:30 +00:00
nicm
4bb48998e0 Fix reverse attribute in status line, GitHub issue 1709. 2019-05-03 10:00:48 +00:00
nicm
5d9e591ae8 Fix up some bits about window-size that seem to have got lost. 2019-05-02 20:12:40 +00:00
Thomas Adam
4d16df9312 Merge branch 'obsd-master' 2019-05-01 09:02:27 +01:00
Nicholas Marriott
18e554aa61 Merge tag '2.9a'
2.9a
2019-05-01 07:29:23 +01:00
Nicholas Marriott
4cb13d95ba Add to CHANGES. 2019-05-01 07:16:20 +01:00
Nicholas Marriott
e36d6ee06a Version 2.9a. 2019-05-01 07:12:14 +01:00
nicm
901eed7b71 Do not loop forever if there is a nonprintable character in the format. 2019-05-01 07:12:02 +01:00
nicm
750d5830c2 Don't redraw control clients, from George Nachman. 2019-05-01 07:08:04 +01:00
nicm
e286178aa7 Unbreak main-vertical and main-horizontal layouts. 2019-05-01 07:07:52 +01:00
nicm
c176361788 Remove unused variable from Thomas Adam. 2019-05-01 06:07:14 +00:00
Thomas Adam
dc7e53897a Merge branch 'obsd-master' 2019-04-30 21:02:26 +01:00
nicm
429c4bc51b Fix user options after show-hooks merge, GitHub issue 1704. 2019-04-30 18:02:03 +00:00
Nicholas Marriott
1156d91cf8 Simple -C sanity test. 2019-04-30 18:39:07 +01:00
Thomas Adam
4c5b0fbbcc Merge branch 'obsd-master' 2019-04-30 09:02:29 +01:00
nicm
5a288b1efe Don't redraw control clients, from George Nachman. 2019-04-30 06:21:30 +00:00
nicm
82c789ee58 Fix memory leak in window tree search, from Amos Bird. 2019-04-30 06:19:51 +00:00
Nicholas Marriott
7e0f9ab3eb Don't think I will do this. 2019-04-29 21:48:15 +01:00
Nicholas Marriott
87bd8965c6 Add to CHANGES & remove from TODO. 2019-04-29 20:18:07 +01:00
Thomas Adam
2aa517c805 Merge branch 'obsd-master' 2019-04-29 09:02:25 +01:00
nicm
ec81bd2399 Add support for keys to jump between matching brackets - C-M-f and C-M-b
in emacs, % in vi. Suggested by and help from Chris Barber in GitHub
issue 1666.
2019-04-29 06:55:21 +00:00
Thomas Adam
3ab229da70 Merge branch 'obsd-master' 2019-04-28 23:02:30 +01:00
Nicholas Marriott
2cecabd75e Fix gseq use in RGB colour script. 2019-04-28 22:16:34 +01:00
nicm
c4b0da5513 Support multiple occurances of the same argument. Use this for a new
flag -e to new-window, split-window, respawn-window, respawn-pane to
pass environment variables into the newly created process. From Steffen
Christgau in GitHub issue 1697.
2019-04-28 20:05:50 +00:00
Thomas Adam
5489796737 Merge branch 'obsd-master' 2019-04-27 20:09:07 +01:00
Thomas Adam
85f09f9a4c Merge branch 'obsd-master' 2019-04-26 13:02:37 +01:00
Nicholas Marriott
293fd0d258 Update CHANGES and TODO. 2019-04-26 12:44:25 +01:00
nicm
dfb7bb6830 Merge hooks into options and make each one an array option. This allows
multiple commands to be easily bound to one hook. set-hook and
show-hooks remain but they are now variants of set-option and
show-options. show-options now has a -H flag to show hooks (by default
they are not shown).
2019-04-26 11:38:51 +00:00
nicm
f1e14f86c4 Destroy panes before options to avoid crash when forced into a mode by a
hook.
2019-04-26 10:24:26 +00:00
nicm
6644d209d2 Unbreak main-vertical and main-horizontal layouts. 2019-04-26 10:15:40 +00:00
Thomas Adam
7c4a2253e8 Merge branch 'obsd-master' 2019-04-25 21:02:43 +01:00
nicm
2d65bbd941 options_array_item_value cannot return NULL. 2019-04-25 19:36:59 +00:00
nicm
a609e6361a Need a fallback for -2 for aixterm colours. 2019-04-25 19:03:43 +00:00
nicm
32a81e197b Make options_tostring allocate its result instead of using a stack
buffer (needed for something in the future).
2019-04-25 18:18:55 +00:00
Thomas Adam
f2c0605d6d Merge branch 'obsd-master' 2019-04-25 17:02:37 +01:00
nicm
1677bb0dea Need to escape ]. 2019-04-25 15:35:07 +00:00
Nicholas Marriott
dddc544b8f Update CHANGES. 2019-04-25 13:00:32 +01:00
Thomas Adam
643eecde86 Merge branch 'obsd-master' 2019-04-25 09:02:36 +01:00
nicm
567d3e27ab Automatically scroll if dragging to create a selection with the mouse
and the cursor reaches the top or bottom line.
2019-04-25 06:34:57 +00:00
Nicholas Marriott
a2e08b587a Merge branch '2.9-rc' 2019-04-25 07:29:02 +01:00
Nicholas Marriott
cb75ec25c8 2.9 now. 2019-04-24 22:35:23 +01:00
nicm
7d06216289 Do not loop forever if there is a nonprintable character in the format. 2019-04-24 22:34:56 +01:00
Thomas Adam
4ab208ecc8 Merge branch 'obsd-master' 2019-04-24 22:09:57 +01:00
nicm
6aa0bedad2 Use bg not fg when adjusting for aixterm, from Ailin Nemui. 2019-04-24 20:32:31 +00:00
nicm
c6e39976c6 Do not loop forever if there is a nonprintable character in the format. 2019-04-24 20:27:52 +00:00
Thomas Adam
c869366133 Merge branch 'obsd-master' 2019-04-23 23:02:42 +01:00
nicm
b9022e33ea Somehow missed these bits in last commit. 2019-04-23 20:40:03 +00:00
nicm
772b3b7a06 Indicate an array option with a flag rather than a special type so that
in future will not have to be strings.
2019-04-23 20:36:55 +00:00
Thomas Adam
b0d7623b7e Merge branch 'obsd-master' 2019-04-23 13:02:37 +01:00
Thomas Adam
4a96f599f6 Merge branch 'obsd-master' 2019-04-23 11:02:36 +01:00
nicm
564e44adc6 Add -no-clear variants of copy-selection and copy-pipe which do not
clear the selection after copying. Make copy-pipe clear the selection by
default to be consistent with copy-selection. From Avi Halachmi.
2019-04-23 09:39:07 +00:00
nicm
6752f41c2a Do not try to resize if the parent cell is NULL, problem reported by
Sunil Nimmagadda.
2019-04-23 09:15:24 +00:00
Nicholas Marriott
51c09bf2b4 Merge branch '2.9-rc' 2019-04-18 22:14:55 +01:00
Nicholas Marriott
d24a44230a Update CHANGES for 2.9. 2019-04-18 22:12:15 +01:00
Nicholas Marriott
8d752f5aaa Update CHANGES. 2019-04-18 22:11:46 +01:00
Nicholas Marriott
e7827f8bc2 Remove duplicate entry. 2019-04-18 14:16:19 +01:00
Thomas Adam
f980e868dd Merge branch 'obsd-master' 2019-04-18 14:11:22 +01:00
Thomas Adam
3c1f0cfc34 Merge branch 'obsd-master' 2019-04-18 14:08:13 +01:00
nicm
5b9211d827 Copy the code to infer the option type to show-options and document it. 2019-04-18 12:22:07 +00:00
nicm
3f189945d8 Pass target client and session to load_cfg from source-file so formats
work. Reported by Thomas Sattler.
2019-04-18 11:07:28 +00:00
nicm
f3ab05e7cd Update session activity on focus event, from tafryn at gmail dot com. 2019-04-18 10:11:52 +00:00
jmc
2219f7cc73 mark up punctuation-as-macro-args properly; 2019-04-17 16:34:35 +00:00
nicm
1fd3b9ec1c Fix minimum size check on split and size of first cell on spread out
with a pane status line.
2019-04-17 14:44:33 +00:00
nicm
da31eddadc Rewrite main-vertical and horizontal to use the common spread out code
and to handle the case where the panes won't fit into the existing
window size.
2019-04-17 14:44:14 +00:00
nicm
c660e46149 Set the window size as well as the layout size when using the preset
layouts.
2019-04-17 14:43:49 +00:00
nicm
e3b1358bbc Do not let the size of the pane status screen go negative. 2019-04-17 14:41:08 +00:00
nicm
5943cd1907 Document that switch-client can change all of session,window,pane and
check for % in the target as well as ":.".
2019-04-17 14:39:37 +00:00
nicm
78287e27c8 Break new window and pane creation common code from various commands and
window.c into a separate file spawn.c.
2019-04-17 14:37:48 +00:00
Nicholas Marriott
82bc2c87a9 Add to TODO. 2019-04-17 09:10:23 +01:00
nicm
cd4c94f76b Current window style also needs to be tested for default. 2019-04-11 09:34:22 +01:00
Nicholas Marriott
bba1809eac Merge a number of fixes from master for layouts, mostly prompted by testing by
Thomas Sattler.
2019-04-11 09:26:34 +01:00
Nicholas Marriott
e6ee3e9504 Warning fixes from Carlo Marcelo Arenas Belón. 2019-04-10 19:27:09 +01:00
Nicholas Marriott
1c1ec84aa3 Fix minimum size check on split and size of first cell on spread out with a
pane status line.
2019-04-10 14:54:02 +01:00
Nicholas Marriott
f3fcf977e4 Use the right winlink pointer in new-window. 2019-04-10 11:40:59 +01:00
Nicholas Marriott
4a3ac3bd26 Remove unused variable. 2019-04-10 07:27:21 +01:00
Nicholas Marriott
3c5d3a3780 Add PATH_DEFPATH to compat.h from Carlo Marcelo Arenas Belón. 2019-04-09 21:31:50 +01:00
Nicholas Marriott
fe44f90e5b Do not let the size of the pane status screen go negative. 2019-04-09 21:30:03 +01:00
Nicholas Marriott
031e9bc854 Rewrite main-vertical and horizontal to use the common spread out code and to
handle the case where the panes won't fit into the existing window size.
2019-04-09 21:15:00 +01:00
Nicholas Marriott
0cbccc90ab Set the window size as well as the layout size when using the preset layouts
and calculate the sizes correctly.
2019-04-09 20:38:43 +01:00
Nicholas Marriott
71d90c11dd Solaris has no paths.h. 2019-04-09 07:52:54 +01:00
Thomas Adam
2546572e8e Merge branch 'obsd-master' 2019-04-08 21:02:37 +01:00
nicm
835ccbac46 select-word was missing from the command list, from pawel-slowik. 2019-04-08 17:55:51 +00:00
Nicholas Marriott
b5b67c5386 Document that switch-client can change all of session,window,pane and check for
% in the target as well as ":.".
2019-04-08 10:38:50 +01:00
Thomas Adam
fbe488e4de Merge branch 'obsd-master' 2019-04-07 23:02:37 +01:00
nicm
bb629f3be7 Current window style also needs to be tested for default. 2019-04-07 20:18:20 +00:00
Thomas Adam
883a428e27 Linux: remove include for util.h
Linux doesn't require this header.
2019-04-07 15:39:58 +01:00
Nicholas Marriott
e44e2c48dd Do not log NULL command. 2019-04-07 13:16:55 +01:00
Nicholas Marriott
ece737274e Forgot to add the file. 2019-04-07 13:11:55 +01:00
Nicholas Marriott
5ece386cdf Break new window and pane creation common code from various commands and
window.c into a separate file spawn.c.
2019-04-07 13:01:03 +01:00
Nicholas Marriott
7653328ce7 Remove from TODO one thing that I don't think is necessary and one that is
done.
2019-04-07 12:18:40 +01:00
Nicholas Marriott
fc111d2b12 Fix a duplicate entry in CHANGES and remove an item from TODO. 2019-04-07 12:07:26 +01:00
Thomas Adam
04402db616 Merge branch 'obsd-master' 2019-04-05 23:02:36 +01:00
nicm
1b5a8a0f09 Fix some warnings, from Thomas Adam. 2019-04-05 20:32:31 +00:00
Nicholas Marriott
e33b623f21 Merge branch '2.9-rc' 2019-04-04 18:31:54 +01:00
nicm
73b54a0e5f Fix size check for splitw -f and top level pane size for tiled layout,
problems reported by Thomas Sattler.
2019-04-04 18:31:35 +01:00
Thomas Adam
5a97af7961 Merge branch 'obsd-master' 2019-04-04 13:02:37 +01:00
nicm
f4aefb738e Fix size check for splitw -f and top level pane size for tiled layout,
problems reported by Thomas Sattler.
2019-04-04 10:25:35 +00:00
nicm
481c3f3f2e screen_write_fast_copy can no longer assume the target screen is default
(it isn't for the pane status lines).
2019-04-03 09:31:32 +01:00
Thomas Adam
cb039b986e Merge branch 'obsd-master' 2019-04-03 09:02:41 +01:00
nicm
f6c54f3f03 Do not load /etc/tmux.conf if given -f. 2019-04-03 06:43:19 +00:00
nicm
06d58b3b7b screen_write_fast_copy can no longer assume the target screen is default
(it isn't for the pane status lines).
2019-04-03 06:43:04 +00:00
nicm
8968acd678 Silence flag should use the same option as activity, reported by Thomas
Sattler.
2019-04-02 22:20:36 +01:00
Thomas Adam
c9ef144dca Merge branch 'obsd-master' 2019-04-02 21:02:37 +01:00
nicm
09f71ed1b2 Silence flag should use the same option as activity, reported by Thomas
Sattler.
2019-04-02 18:41:24 +00:00
Nicholas Marriott
f0ddc301b7 Add CHANGES. 2019-04-02 17:02:09 +01:00
Nicholas Marriott
916c4c499d Version RC2. 2019-04-02 11:12:24 +01:00
Nicholas Marriott
fac792dc27 Update regress from master. 2019-04-02 11:11:19 +01:00
nicm
bbcfee362f Store and restore cursor across reflow by working out a position based
on unwrapped lines, rather than a grid offset. Fixes problems reported
by Thomas Sattler and Paul de Weerd.
2019-04-02 11:11:12 +01:00
Thomas Adam
bfc1f0ca62 Merge branch 'obsd-master' 2019-04-02 11:02:44 +01:00
nicm
7bcc0d16f2 Add an argument to copy commands to set the prefix for the buffer name,
allows buffers for different sessions to be named separately.
2019-04-02 09:03:39 +00:00
Nicholas Marriott
f03776c262 Don't use a config file in tests. 2019-04-02 09:53:02 +01:00
nicm
ffa4d48967 Store and restore cursor across reflow by working out a position based
on unwrapped lines, rather than a grid offset. Fixes problems reported
by Thomas Sattler and Paul de Weerd.
2019-04-02 08:45:32 +00:00
Nicholas Marriott
79c3fd4f39 Add cursor regression tests. 2019-04-02 09:44:28 +01:00
nicm
6d071c468c Restore a check to stop scrolled lines becoming larger than total lines,
fixes a crash reported by Thomas Sattler.
2019-04-02 07:33:33 +01:00
Thomas Adam
294accea1b Merge branch 'obsd-master' 2019-04-01 21:02:37 +01:00
nicm
792fcb1dbf Restore a check to stop scrolled lines becoming larger than total lines,
fixes a crash reported by Thomas Sattler.
2019-04-01 19:33:38 +00:00
Nicholas Marriott
da359269cb Merge branch '2.9-rc' 2019-03-29 11:20:15 +00:00
nicm
92da105b58 Free old strings after they have been expanded in format_choose. 2019-03-29 11:19:55 +00:00
Thomas Adam
ecc5cea09b Merge branch 'obsd-master' 2019-03-29 10:02:36 +00:00
nicm
d68a17a1df Free old strings after they have been expanded in format_choose. 2019-03-29 09:33:24 +00:00
Nicholas Marriott
52cb7a6382 Merge branch '2.9-rc' 2019-03-29 07:05:50 +00:00
nicm
00fda57ddf Fix offset of list ranges. 2019-03-29 07:05:40 +00:00
Thomas Adam
405bb8435c Merge branch 'obsd-master' 2019-03-29 00:02:36 +00:00
nicm
c6c4960b35 Fix offset of list ranges. 2019-03-28 22:18:46 +00:00
Thomas Adam
2c4f2393ec Merge branch 'obsd-master' 2019-03-28 22:02:37 +00:00
nicm
08bc226527 Expand session and window formats for buffer filters. 2019-03-28 21:05:15 +00:00
Thomas Adam
6b38334b28 Merge branch 'obsd-master' 2019-03-27 14:02:36 +00:00
nicm
c1f0918f8a Fix stop-selection, from Avi Halachmi. 2019-03-27 13:25:11 +00:00
Thomas Adam
6861045d38 Merge branch 'obsd-master' 2019-03-26 22:02:36 +00:00
nicm
9f8d193b11 Break copy mode commands into individual functions instead of a big load
of if statements.
2019-03-26 21:01:19 +00:00
Nicholas Marriott
a13e57f701 Update TODO. 2019-03-26 17:04:47 +00:00
Nicholas Marriott
e722ba38e3 There is no examples directory anymore. 2019-03-26 15:10:05 +00:00
Nicholas Marriott
b1dc2b5353 Merge branch '2.9-rc' 2019-03-26 15:05:41 +00:00
Nicholas Marriott
e0e08fcd2d Update CHANGES & TODO. 2019-03-26 15:05:28 +00:00
Nicholas Marriott
0a913b09cf For 3.0. 2019-03-26 14:38:20 +00:00
Nicholas Marriott
4f7a5d1e40 2.9 bits. 2019-03-26 14:37:27 +00:00
Thomas Adam
6ac84585e6 Merge branch 'obsd-master' 2019-03-25 20:02:38 +00:00
nicm
d21f8ecc13 Add StatusDefault binding for the mouse on any otherwise unassigned
parts of the status line, from Avi Halachmi.
2019-03-25 18:59:55 +00:00
Thomas Adam
5e2150cf18 Merge branch 'obsd-master' 2019-03-25 16:00:36 +00:00
Thomas Adam
a07ad6b5a3 Merge branch 'obsd-master' 2019-03-25 15:57:47 +00:00
nicm
ff4d7d541f Fix columns of cursor_character format in list. 2019-03-25 14:29:36 +00:00
Nicholas Marriott
e8f4ca6a52 Tweaks to example config. 2019-03-25 12:05:58 +00:00
Nicholas Marriott
a084f2dcb7 Add to TODO. 2019-03-25 10:06:03 +00:00
nicm
517d673dbe Ignore mouse on status line which are not part of a range, GitHub issue 1649. 2019-03-25 09:22:09 +00:00
nicm
b4a301f8fe Clarify that styles can be space or comma separated, from Stephen Zapatka. 2019-03-22 10:45:17 +00:00
nicm
04a1fc9d36 I forgot to document resize-window, window-size and default-size;
reminded by okan@.
2019-03-22 09:33:04 +00:00
Thomas Adam
0292243b29 Merge branch 'obsd-master' 2019-03-20 20:02:37 +00:00
Nicholas Marriott
ef38a420b2 Update TODO. 2019-03-20 20:02:13 +00:00
Nicholas Marriott
7536d57b16 Update TODO. 2019-03-20 19:26:20 +00:00
nicm
9ee1a8f701 Improve cursor positioning after reflow by storing the position as an
offset into the entire history before reflow and restoring it aftewards.
2019-03-20 19:19:11 +00:00
Nicholas Marriott
0e0f2f765b Update CHANGES. 2019-03-20 14:01:46 +00:00
Thomas Adam
bff957a475 Merge branch 'obsd-master' 2019-03-20 08:02:38 +00:00
nicm
ed962e7612 Include function name in logging. 2019-03-20 07:30:05 +00:00
nicm
458b87150b Do not leak ranges on error. 2019-03-20 07:28:31 +00:00
nicm
ae46a19b8e Ignore invalid styles rather than throwing away the whole format, this
matches what we used to do.
2019-03-20 07:24:03 +00:00
nicm
3b959c05ff Bit more logging to show drawing errors. 2019-03-20 07:13:02 +00:00
Thomas Adam
46f642b030 Merge branch 'obsd-master' 2019-03-19 22:02:36 +00:00
nicm
8b74e959ef Include window-status-style and window-status-current style in the format. 2019-03-19 21:09:51 +00:00
Thomas Adam
320237fdb8 Merge branch 'obsd-master' 2019-03-19 20:02:37 +00:00
nicm
161b57869e Add a cursor_character format. 2019-03-19 19:01:50 +00:00
Nicholas Marriott
92732a2540 Add to TODO. 2019-03-19 14:39:55 +00:00
Thomas Adam
b3eebdec48 Merge branch 'obsd-master' 2019-03-19 14:02:36 +00:00
nicm
b24c9e34a9 Rename the first KEY BINDINGS section to DEFAULT KEY BINDINGS. 2019-03-19 13:35:42 +00:00
Thomas Adam
073d439965 Merge branch 'obsd-master' 2019-03-19 00:02:39 +00:00
Thomas Adam
f956c17c09 Merge branch 'obsd-master' 2019-03-18 22:02:36 +00:00
nicm
0406ec0ec2 Free temporary screens when writing format. 2019-03-18 21:55:04 +00:00
nicm
f34ebfed76 The individual -fg, -bg and -attr options have been deprecated (in
favour of -style), undocumented and hidden from show-options since
2014. Remove them, except for status-fg and status-bg.
2019-03-18 21:46:01 +00:00
Thomas Adam
962f255ee8 Merge branch 'obsd-master' 2019-03-18 21:24:49 +00:00
nicm
c62404673e Add some bits to the STATUS LINE section about the new option. 2019-03-18 21:01:04 +00:00
nicm
979313832c Extend the #[] style syntax and use that together with previous format
changes to allow the status line to be entirely configured with a single
option.

Now that it is possible to configure their content, enable the existing
code that lets the status line be multiple lines in height. The status
option can now take a value of 2, 3, 4 or 5 (as well as the previous on
or off) to configure more than one line. The new status-format array
option configures the format of each line, the default just references
the existing status-* options, although some of the more obscure status
options may be eliminated in time.

Additions to the #[] syntax are: "align" to specify alignment (left,
centre, right), "list" for the window list and "range" to configure
ranges of text for the mouse bindings.

The "align" keyword can also be used to specify alignment of entries in
tree mode and the pane status lines.
2019-03-18 20:53:33 +00:00
Thomas Adam
1d6fe43c7b Merge branch 'obsd-master' 2019-03-18 18:02:38 +00:00
Thomas Adam
4cbf596dc5 Merge branch 'obsd-master' 2019-03-18 15:30:55 +00:00
nicm
d738d51688 Mode init needs to be fired with the mode on the list or it will not be
resized correctly.
2019-03-18 15:25:36 +00:00
Thomas Adam
acb2413852 Merge branch 'obsd-master' 2019-03-18 15:07:51 +00:00
nicm
2628af573d Add format variables for the default formats for the various modes
(tree_mode_format and so on) and add a -a flag to display-message to
list variables with values.
2019-03-18 14:10:25 +00:00
Nicholas Marriott
aa2b3472c5 Update TODO. 2019-03-18 12:00:10 +00:00
nicm
ce6be7afd4 Make array options a sparse tree instead of an array of char * and
remove the size limit.
2019-03-18 11:58:40 +00:00
nicm
d2d43987d0 With force, kill previous job before starting new. Fixes problem
reported by Scott Mcdermott in GitHub issue 1627.
2019-03-18 09:46:42 +00:00
nicm
bd3332b211 Break description of styles into its own section. 2019-03-17 19:33:12 +00:00
Nicholas Marriott
3a298454ce Add to TODO. 2019-03-17 08:05:58 +00:00
nicm
b588b1729a Use a pointer for the active screen in the status line instead of
copying them around all the time.
2019-03-16 19:12:13 +00:00
nicm
818fda0363 Give status_save_old the client so it can do the reinit too. 2019-03-16 17:53:55 +00:00
nicm
b4f5b99e4b Tidy and rename some bits of status line code. 2019-03-16 17:14:07 +00:00
nicm
e8b33af780 Add a way to set individual defaults for an array option. 2019-03-15 21:54:47 +00:00
nicm
1d306e926a Add a : to make error messages clearer. 2019-03-15 15:20:00 +00:00
nicm
33595a255f Copy recursion counter into new formats when looping. 2019-03-15 15:02:25 +00:00
nicm
85044a634b Move status line free into its own function. 2019-03-15 14:46:58 +00:00
nicm
2d71bef0ca Remove unused member of struct client. 2019-03-15 10:48:05 +00:00
nicm
f6d34f066c Only print format logging when the flag is set, even if also sending to log_debug. 2019-03-15 10:22:57 +00:00
nicm
672c49d512 The pane and window loops need to pass the window and pane tags when
they build their format.
2019-03-15 10:07:24 +00:00
nicm
27578815da Add a -v flag to display-message to show verbose messages as the format
is parsed, this gives the user a way to debug problems with formats
rather than just being confronted with (for example) a blank status
line.
2019-03-15 10:04:13 +00:00
nicm
25e2e22791 Add a limit on how far format_expand can recurse. 2019-03-14 23:34:41 +00:00
nicm
10d60faba5 Store the time in the format tree rather than passing it around. 2019-03-14 23:14:27 +00:00
Thomas Adam
2c755e3c55 Merge branch 'obsd-master' 2019-03-14 22:02:39 +00:00
nicm
bace79a571 Remove some unnecessary temporary variables and be much less strict
about spacing in style_parse.
2019-03-14 21:46:08 +00:00
nicm
4206bcc10e Add format flags for start and end window. 2019-03-14 21:41:30 +00:00
nicm
38064e7593 Add T format modifier like E but also do strftime(3). 2019-03-14 21:31:43 +00:00
nicm
1416ceb575 Accept 0 time as a shorthand for now to format_expand_time. 2019-03-14 21:27:26 +00:00
Thomas Adam
d58bccfc63 Merge branch 'obsd-master' 2019-03-14 20:02:38 +00:00
nicm
9bd4b96766 Fix ED1 (clear end of screen), reported by Marc Reisner. 2019-03-14 17:58:52 +00:00
Thomas Adam
0b32fa81b6 Merge branch 'obsd-master' 2019-03-14 12:02:41 +00:00
nicm
0425e3178d A little tidying in style_parse. 2019-03-14 10:19:52 +00:00
nicm
13f9a061ac Add a wrapper (struct style) around styles rather than using the
grid_cell directly. There will be some non-cell members soon.
2019-03-14 09:53:52 +00:00
Thomas Adam
f33d2ab29e Merge branch 'obsd-master' 2019-03-14 08:02:37 +00:00
nicm
1e9f8a3523 Missing space in capture-pane usage, from Ben Boeckel.
Also man page fixed from jmc.
2019-03-14 06:36:21 +00:00
nicm
2fbd491ff0 Add actual HPA (\033[`), the existing one is CHA. From Marc Reisner. 2019-03-14 06:33:43 +00:00
Thomas Adam
81b393a493 Merge branch 'obsd-master' 2019-03-14 00:02:37 +00:00
nicm
5755bfc619 Need to set attributes before clearing. 2019-03-13 22:01:22 +00:00
nicm
10f0094be9 The pane's style should be initialized to default before parsing the
argument.
2019-03-13 21:39:21 +00:00
Thomas Adam
786f5e505e Merge branch 'obsd-master' 2019-03-13 20:02:36 +00:00
nicm
6dffbc4849 Tweak format_replace logging. 2019-03-13 18:09:12 +00:00
Thomas Adam
e6fd429d58 Merge branch 'obsd-master' 2019-03-13 16:02:41 +00:00
nicm
95ab1aaaec Add formats to list sessions, windows or panes. 2019-03-13 15:37:28 +00:00
Nicholas Marriott
f628afc850 Update TODO. 2019-03-13 14:51:19 +00:00
nicm
49f04a997a Apply length limits and substitution even to literal formats. 2019-03-13 14:27:17 +00:00
Nicholas Marriott
1aeac384f3 Add to TODO. 2019-03-13 14:20:58 +00:00
nicm
9032ac2a05 Add E: format to expand a format twice (useful to expand the value of an
option).
2019-03-13 14:19:54 +00:00
nicm
71e00c718c Make format parsing build the modifiers into a list, standardize how
arguments are given and allow multiple modifiers on a format (separated
by ;).
2019-03-13 14:10:34 +00:00
Nicholas Marriott
7a6b21de65 Add to TODO. 2019-03-13 09:30:42 +00:00
Nicholas Marriott
4f5cb88c2b Add to TODO. 2019-03-13 09:30:42 +00:00
Thomas Adam
0e6eda02a6 Merge branch 'obsd-master' 2019-03-13 08:02:35 +00:00
nicm
feaa5660a3 Do not use origin for VPA. 2019-03-13 07:34:36 +00:00
Thomas Adam
b03f58b977 Merge branch 'obsd-master' 2019-03-13 00:02:38 +00:00
nicm
b2bc34af12 Set a flag on cells are genuinely empty (cleared and never written to)
and use tty_clear_line (which will choose the best escape sequence) to
clear any batches of cells with that flag when redrawing a line from the
stored screen.
2019-03-12 23:21:45 +00:00
Thomas Adam
400529eea0 Merge branch 'obsd-master' 2019-03-12 22:02:42 +00:00
nicm
938156d73b DECRC and DECSC apparently need to preserve origin mode as well, based
on a fix from Marc Reisner.
2019-03-12 20:02:47 +00:00
Thomas Adam
ba4a884d75 Merge branch 'obsd-master' 2019-03-12 20:02:38 +00:00
nicm
2796ae81d0 Fix HPA in origin mode. 2019-03-12 18:30:08 +00:00
nicm
f3f534a3a0 Tidy up a lot of &ictx->ctx by using a local variable. 2019-03-12 18:26:57 +00:00
Nicholas Marriott
6c3ee42568 Add a couple of things. 2019-03-12 17:59:46 +00:00
Nicholas Marriott
2f0ffe6adb Add to TODO. 2019-03-12 17:52:22 +00:00
Nicholas Marriott
4002dbf0c1 Fix session size regress. 2019-03-12 17:36:58 +00:00
Thomas Adam
162d3cb1f4 Merge branch 'obsd-master' 2019-03-12 16:02:37 +00:00
Thomas Adam
7d2004a8dd Merge branch 'obsd-master' 2019-03-12 14:02:40 +00:00
Nicholas Marriott
860acecc0d Fix up regress test for control client size. 2019-03-12 13:57:06 +00:00
nicm
028f9d1d87 Fix resizing of control clients, should be ignored until SIZECHANGED flag set. 2019-03-12 13:56:30 +00:00
nicm
303d20a758 Fix wrapping after origin mode change. 2019-03-12 13:14:14 +00:00
nicm
3f0efc050a When asked for a window index, return it even if the window exists. 2019-03-12 13:14:04 +00:00
nicm
7804fa1b82 Revert to not clearing history on RIS, apparently some bootloaders send
this and it doesn't really do any harm.
2019-03-12 12:58:40 +00:00
nicm
7b819357ff Tweak target debug logging. 2019-03-12 12:49:46 +00:00
Nicholas Marriott
595b52490e Add to TODO. 2019-03-12 12:12:35 +00:00
Thomas Adam
3ec05e9405 Merge branch 'obsd-master' 2019-03-12 12:02:42 +00:00
Nicholas Marriott
f8a30e1588 Update CHANGES. 2019-03-12 11:20:21 +00:00
nicm
3f6bfbaf2b Allow multiple modes to be open in a pane. A stack of open modes is kept
and the previous restored when the top is exited. If a mode that is
already on the stack is entered, the existing instance is moved to the
top as the active mode rather than being opened new.
2019-03-12 11:16:49 +00:00
Thomas Adam
95d340cc4f Merge branch 'obsd-master' 2019-03-12 10:02:39 +00:00
nicm
ff4c80d53d Add support for origin mode (DECOM, SM/RM ?6), from Marc Reisner. 2019-03-12 07:39:27 +00:00
Thomas Adam
bc72cf2f52 Merge branch 'obsd-master' 2019-03-08 12:02:39 +00:00
nicm
de730f68a4 Make the mode used to view command output (a variant of copy mode) use
its own mode definition struct with a different init function rather
than calling special setup functions.
2019-03-08 10:34:20 +00:00
nicm
9cc04a0f9a Do not use window mode entry after free. 2019-03-08 10:29:25 +00:00
Thomas Adam
349aeb806a Merge branch 'obsd-master' 2019-03-07 22:02:42 +00:00
nicm
f98c66ece8 Add a separate mode struct for the active window mode if any. 2019-03-07 20:24:21 +00:00
Thomas Adam
a1009e7bd3 Merge branch 'obsd-master' 2019-03-07 20:02:41 +00:00
nicm
3c24bc5617 Tidy changing the mode into window_copy_init_for_output. 2019-03-07 19:34:22 +00:00
nicm
7f093fcddc Make adding mode formats a function pointer as well. 2019-03-07 19:01:21 +00:00
Nicholas Marriott
5a564a0c1a Add to TODO. 2019-03-07 15:34:24 +00:00
Thomas Adam
9ebd630675 Merge branch 'obsd-master' 2019-03-04 12:01:28 +00:00
nicm
5cdd578906 Fix sense of aggressive-resize flag. 2019-03-04 09:29:52 +00:00
nicm
a870c255c4 Don't set client offset if client is not a terminal 2019-03-04 09:29:40 +00:00
Thomas Adam
d5c837904b Merge branch 'obsd-master' 2019-02-16 20:02:36 +00:00
nicm
fa33603dc1 Do not look at next key byte if the length is 0, originally from Shingo
NISHIOKA in GitHub issue 1601.
2019-02-16 19:04:34 +00:00
Thomas Adam
fa8294436c Merge branch 'obsd-master' 2019-02-16 14:02:37 +00:00
nicm
82f0c859a2 Use starting client cwd in config file, GitHub issue 1606. 2019-02-16 11:42:08 +00:00
Thomas Adam
9768091ee4 Merge branch 'obsd-master' 2019-02-09 20:02:36 +00:00
nicm
f9c396db41 Completion of command-alias members. 2019-02-09 18:18:36 +00:00
Nicholas Marriott
bdb7e48cba Redirect which stderr. 2019-02-06 14:45:35 +00:00
Thomas Adam
c42e89a598 Merge branch 'obsd-master' 2019-02-06 08:02:37 +00:00
nicm
afd3127d89 Add -b to display-panes like run-shell, GitHub issue 1559. 2019-02-06 07:36:06 +00:00
Thomas Adam
4ab3b18b36 Merge branch 'obsd-master' 2019-01-20 18:02:36 +00:00
nicm
2ea22fce5e Should use DECFRA if not default, not if default. From Karl Beldan. 2019-01-20 15:57:27 +00:00
Thomas Adam
cd8a7fb07b Merge branch 'obsd-master' 2019-01-15 14:02:37 +00:00
nicm
cd39920abd Should save the bg colour when setting it to default, not the fg. 2019-01-15 12:08:53 +00:00
Thomas Adam
469a9e9439 Merge branch 'obsd-master' 2019-01-15 12:02:36 +00:00
nicm
34c0807be6 Do not highlight characters which will not be copied, reported by
Jaroslaw Rzeszotko.
2019-01-15 09:56:31 +00:00
Thomas Adam
c9d482ab48 Merge branch 'obsd-master' 2018-12-18 14:02:40 +00:00
nicm
bde0224deb Pass window into mode functions. 2018-12-18 13:20:44 +00:00
Thomas Adam
b6cdac05c7 Merge branch 'obsd-master' 2018-12-18 00:02:37 +00:00
nicm
4e3d661284 Fix parsing of empty colon-separated fields, reported by Siarhei Siniak. 2018-12-17 21:52:59 +00:00
Thomas Adam
1c5093c1c4 Merge branch 'obsd-master' 2018-11-30 10:02:37 +00:00
nicm
67254ed8df Clear PANE_EXITED flag when starting new child process in case the pane
has been respawned.
2018-11-30 08:44:40 +00:00
Nicholas Marriott
6cf2f74fe9 osdep_get_cwd for NetBSD, from Leonardo Taccari. 2018-11-29 10:37:27 +00:00
Thomas Adam
1ed994a6c8 Merge branch 'obsd-master' 2018-11-28 12:02:36 +00:00
nicm
40d246b29c Handle UTF-8 in word-separators option, GitHub issue 1551. 2018-11-28 11:20:13 +00:00
Thomas Adam
2977317243 Merge branch 'obsd-master' 2018-11-22 12:02:38 +00:00
nicm
3a7b9d5735 Do not use PWD unless it actually matches the real working directory. 2018-11-22 10:36:40 +00:00
Nicholas Marriott
2eca63b98e Add to TODO. 2018-11-21 09:50:53 +00:00
Nicholas Marriott
c4b04b1624 Fixes for GNU/kFreeBSD from James Clarke. 2018-11-21 08:50:22 +00:00
Thomas Adam
efd01f3bfd Merge branch 'obsd-master' 2018-11-19 14:02:41 +00:00
nicm
749f67b7d8 evbuffer_new and bufferevent_new can both fail (when malloc fails) and
return NULL. GitHub issue 1547.
2018-11-19 13:35:40 +00:00
Thomas Adam
a7da2357a5 Merge branch 'obsd-master' 2018-11-15 12:02:37 +00:00
kn
f103927a52 Add [template] to display-panes and choose-{buffer,client,tree} usage
OK nicm
2018-11-15 10:38:53 +00:00
Thomas Adam
0fd73f238d Merge branch 'obsd-master' 2018-11-13 12:02:38 +00:00
nicm
50cdfc06fb Initialize context property in alignment test handler function. 2018-11-13 11:36:37 +00:00
Thomas Adam
3c6cdf0115 Merge branch 'obsd-master' 2018-11-12 16:02:37 +00:00
nicm
86e648d906 Allow style #[] in mode formats. 2018-11-12 14:18:10 +00:00
Thomas Adam
849d06c0df Merge branch 'obsd-master' 2018-11-08 20:02:37 +00:00
nicm
09aee53763 It isn't possible to specify buffer name to copy mode commands now, so
remove the function argument.
2018-11-08 18:49:19 +00:00
Thomas Adam
4efba0bf9f Merge branch 'obsd-master' 2018-11-07 10:02:39 +00:00
nicm
0c7f64458f If a non-repeating key is used when repeating, it should be treated as
an entirely new key press, not checked in root table and ignored if not
found. GitHub issue 1513.
2018-11-07 08:06:28 +00:00
Nicholas Marriott
ff77010f70 Add to TODO. 2018-11-07 08:00:15 +00:00
nicm
7339845c01 There is no reason wait-for has to be restricted to outside tmux. 2018-11-07 07:58:16 +00:00
Thomas Adam
99072e1d81 Merge branch 'obsd-master' 2018-11-06 16:02:37 +00:00
nicm
f9881b3b5d Correctly unzoom and redraw panes in switch-client. 2018-11-06 15:13:13 +00:00
Thomas Adam
b1ad075d11 Merge branch 'obsd-master' 2018-10-31 12:02:38 +00:00
nicm
ef904cfef2 Reset all flags in screen_write_reset, reported by Benjamin Poirier. 2018-10-31 10:05:47 +00:00
Thomas Adam
ddffda4da5 Merge branch 'obsd-master' 2018-10-28 18:02:36 +00:00
nicm
d5b92ac37e Do not printf NULL. 2018-10-28 16:10:02 +00:00
Thomas Adam
0a54a07909 Merge branch 'obsd-master' 2018-10-28 16:02:37 +00:00
nicm
65dd7345e0 Do not check for a key again without an escape if only \033 is present. 2018-10-28 15:34:27 +00:00
Nicholas Marriott
0cefdff1b6 Add to CHANGES. 2018-10-26 11:36:36 +01:00
Thomas Adam
e771f10dc6 Merge branch 'obsd-master' 2018-10-25 17:02:42 +01:00
nicm
fc41bf46ac Add a "terminal" colour which can be used instead of "default" in style
options for the terminal default colour, bypassing any inheritance from
other options. Prompted by a discussion with abieber@.
2018-10-25 15:13:38 +00:00
Nicholas Marriott
2808f8261c Tweak wording. 2018-10-19 08:38:12 +01:00
Nicholas Marriott
c234032fcf Do not use master here. 2018-10-19 08:37:31 +01:00
Nicholas Marriott
bc6211cca5 Instead of "master" for the version number, use "next-X.X". It is more
useful to include the next version number.
2018-10-19 08:35:23 +01:00
Thomas Adam
164590e34c Merge branch 'obsd-master' 2018-10-18 15:02:38 +01:00
nicm
9feb35b7c4 Document new refresh-client flags. 2018-10-18 13:03:45 +00:00
Thomas Adam
f44d02c7f5 Merge branch 'obsd-master' 2018-10-18 11:09:54 +01:00
nicm
646995384d Support for windows larger than visible on the attached client. This has
been a limitation for a long time.

There are two new options, window-size and default-size, and a new
command, resize-window. The force-width and force-height options and the
session_width and session_height formats have been removed.

The new window-size option tells tmux how to work out the size of
windows: largest means it picks the size of the largest session,
smallest the smallest session (similar to the old behaviour) and manual
means that it does not automatically resize windows. The default is
currently largest but this may change. aggressive-resize modifies the
choice of session for largest and smallest as it did before.

If a window is in a session attached to a client that is too small, only
part of the window is shown. tmux attempts to keep the cursor visible,
so the part of the window displayed is changed as the cursor moves (with
a small delay, to try and avoid excess redrawing when applications
redraw status lines or similar that are not currently visible). The
offset of the visible portion of the window is shown in status-right.

Drawing windows which are larger than the client is not as efficient as
those which fit, particularly when the cursor moves, so it is
recommended to avoid using this on slow machines or networks (set
window-size to smallest or manual).

The resize-window command can be used to resize a window manually. If it
is used, the window-size option is automatically set to manual for the
window (undo this with "setw -u window-size"). resize-window works in a
similar way to resize-pane (-U -D -L -R -x -y flags) but also has -a and
-A flags. -a sets the window to the size of the smallest client (what it
would be if window-size was smallest) and -A the largest.

For the same behaviour as force-width or force-height, use resize-window
-x or -y, and "setw -u window-size" to revert to automatic sizing..

If the global window-size option is set to manual, the default-size
option is used for new windows. If -x or -y is used with new-session,
that sets the default-size option for the new session.

The maximum size of a window is 10000x10000. But expect applications to
complain and much higher memory use if making a window excessively
big. The minimum size is the size required for the current layout
including borders.

The refresh-client command can be used to pan around a window, -U -D -L
-R moves up, down, left or right and -c returns to automatic cursor
tracking. The position is reset when the current window is changed.
2018-10-18 08:38:01 +00:00
Nicholas Marriott
2dfdb55ace Handle pan correctly when the terminal is bigger than the window. 2018-10-18 09:24:15 +01:00
nicm
a51668ca06 Support OSC 52 ? to read the top buffer inside tmux (when set-clipboard
is changed to on), also add refresh-client -l to ask tmux to use the
same mechanism to get the clipboard from the terminal outside
tmux. GitHub issue 1477.
2018-10-18 08:04:14 +00:00
nicm
bc0e527f32 Support for extended underline styles on terminals which offer them,
enabled by adding the Smulx capability with terminal-overrides (add
something like ',vte*:Smulx=\E[4\:%p1%dm'). GitHub issue 1492.
2018-10-18 07:57:57 +00:00
Nicholas Marriott
f54f171d5c Merge branch '2.8-rc' 2018-10-17 19:33:43 +01:00
Nicholas Marriott
01918cb017 tmux 2.8. 2018-10-17 19:29:35 +01:00
Nicholas Marriott
a2c52d9f26 Add to TODO. 2018-10-16 14:16:48 +01:00
Nicholas Marriott
407075d8c7 Add to TODO. 2018-10-16 14:12:33 +01:00
Nicholas Marriott
cdd8c93f54 Add to TODO file. 2018-10-15 09:09:40 +01:00
Nicholas Marriott
c88e945bc5 Support OSC 52 ? to read the top buffer inside tmux, also add
refresh-client -l to get the clipboard outside tmux. GitHub issue
1477.
2018-10-11 16:20:14 +01:00
Nicholas Marriott
018f1b8a80 Use :: for escaping : in terminal-overrides not \:. 2018-10-08 19:42:55 +01:00
Nicholas Marriott
4b9e76aaaa Support for extended underline styles, enabled by adding the Smulx
capability with terminal-overrides (add something like
'vte*:Smulx=\E[4\:%p1%dm'). GitHub issue 1492.
2018-10-08 13:21:37 +01:00
Nicholas Marriott
46847e9b2e Update TODO. 2018-10-08 13:06:37 +01:00
Nicholas Marriott
1952b3f746 Update CHANGES. 2018-10-07 15:06:40 +01:00
Nicholas Marriott
546060f340 Update TODO. 2018-10-07 15:01:41 +01:00
Thomas Adam
c44bb2df17 Merge branch 'obsd-master' 2018-10-03 17:02:38 +01:00
nicm
f7c85f3ed8 Do not move the cursor when the mouse wheel is used, GitHub issue 1493. 2018-10-03 15:27:55 +00:00
Nicholas Marriott
5a7cf897f2 Correctly check offset for drawing multiple cells, GitHub issue 1481. 2018-10-01 19:47:58 +01:00
Nicholas Marriott
8053b65f1e Fix select-pane -m, GitHub issuie 1490. 2018-09-28 09:38:22 +01:00
Thomas Adam
a00cdcdfcb Merge branch 'obsd-master' 2018-09-27 11:02:37 +01:00
nicm
228e1a3951 Use same working directory rules for jobs as new windows rather than
always starting in home, GitHub issue 1488.
2018-09-27 07:43:18 +00:00
Nicholas Marriott
ebaf54251a Add formats for when window is larger than client, and show offset in
status-right by default when larger.
2018-09-26 18:41:18 +01:00
Nicholas Marriott
b74b047730 More of revert. 2018-09-26 16:49:03 +01:00
Nicholas Marriott
04c6db2d0f Revert "Add a B flag to mark windows bigger than the client."
This reverts commit b4e74f4310.
2018-09-26 16:42:29 +01:00
Nicholas Marriott
6abb62df1e Change the B into a +. 2018-09-25 21:57:29 +01:00
Thomas Adam
7cf00d6b72 Merge branch 'obsd-master' 2018-09-25 17:02:41 +01:00
nicm
7d59f82cf9 Allow panes to be 1 line or column by redrawing instead of using the
scroll region, from Soeren Tempel in GitHub issue 1487.
2018-09-25 14:27:20 +00:00
Nicholas Marriott
cbf1504fca Do not clamp to needed size since it may be too big. 2018-09-25 15:15:44 +01:00
Nicholas Marriott
83b2d5c513 window_printable_flags needs an additional argument. 2018-09-25 09:55:49 +01:00
Nicholas Marriott
b4e74f4310 Add a B flag to mark windows bigger than the client. 2018-09-25 09:54:47 +01:00
Nicholas Marriott
26d73a7736 Ignore clients that are suspended or exiting. 2018-09-25 09:48:48 +01:00
Nicholas Marriott
57069287a1 Add to TODO. 2018-09-25 08:27:53 +01:00
Thomas Adam
4799f43298 Merge branch 'obsd-master' 2018-09-24 17:02:38 +01:00
nicm
7bc6c105b7 Only include pane status in minimum size if it is turned on, GitHub
issue 1480.
2018-09-24 15:29:56 +00:00
Nicholas Marriott
ad71e7f9d2 Calculate size when trimming RHS correctly. 2018-09-24 12:17:29 +01:00
Nicholas Marriott
71d2ab184b Fix up merge. 2018-09-12 07:15:27 +01:00
Thomas Adam
c067af8e7d Merge branch 'obsd-master' 2018-09-11 20:11:11 +01:00
Nicholas Marriott
3fa538181b Restore window_pane_visible for drawing panes and borders, fixes issue
1458 reported by Felix Rosencrantz, problem located by Avi Halachmi.
2018-09-11 18:34:53 +01:00
nicm
be2201200f The cursor position is limited to the margins for CUF and CUB, so turn
margins off for printing cells (like most everything else already
does). Problem reported by Thomas Sattler.
2018-09-11 17:31:01 +00:00
Nicholas Marriott
84df87011c x,y -> px,py. 2018-09-11 09:39:28 +01:00
Thomas Adam
5e36d52651 Merge branch 'obsd-master' 2018-09-11 09:21:16 +01:00
nicm
bd9133b31d Do not check for mouse events on pane borders when zoomed, based on a
fix from Avi Halachmi.
2018-09-11 06:37:54 +00:00
Thomas Adam
9b32758a0c Merge branch 'obsd-master' 2018-09-10 09:02:39 +01:00
Nicholas Marriott
5aa435a9f0 window_get_active_at needs to check visible also. 2018-09-10 07:51:11 +01:00
nicm
1b92afa799 Do not clear selection when searching. 2018-09-10 06:48:01 +00:00
Nicholas Marriott
a618271e12 Bring back window_pane_visible to stop input going to panes which are
hidden by zoom.
2018-09-10 07:19:17 +01:00
Nicholas Marriott
8598fd1bc5 Add to TODO. 2018-09-09 07:52:28 +01:00
Nicholas Marriott
59df942e09 Fixes to resize-window from Ben Boeckel. 2018-09-05 08:43:58 +01:00
Nicholas Marriott
621bb15b83 Cast parameters to tparm, from Christos Zoulas via Leonardo Taccari. 2018-09-05 08:42:17 +01:00
Thomas Adam
8e24b0bb3e Makefile.am: Add space between -f and argument
Required for some (older) aek instance -- namely NetBSD.
2018-09-04 13:13:32 +01:00
Thomas Adam
0c07b10b30 Merge branch 'obsd-master' 2018-09-03 11:02:39 +01:00
nicm
8f9491ddfe Allow a large line number to go to the end with goto-line, from Mark
Kelly in GitHub issue 1460.
2018-09-03 08:51:43 +00:00
nicm
9bab73f489 Fix selection test, from Takeshi Banse. 2018-09-03 08:47:27 +00:00
Nicholas Marriott
4e867202e8 Add to TODO. 2018-08-31 14:10:51 +01:00
Thomas Adam
e27b588b6c Merge branch 'obsd-master' 2018-08-29 21:02:37 +01:00
Nicholas Marriott
479cac4896 Fix target line for fast path in tty_draw_pane. 2018-08-29 20:52:27 +01:00
nicm
95e3e363ff Reset line flag when clearing selection, GitHub issue 1454. 2018-08-29 18:54:23 +00:00
Nicholas Marriott
7637518b07 Fix refresh-client flags. 2018-08-29 18:59:43 +01:00
Nicholas Marriott
9263a65b5f Update TODO. 2018-08-29 18:52:04 +01:00
Thomas Adam
b29028a914 Merge branch 'obsd-master' 2018-08-29 13:02:38 +01:00
Thomas Adam
1ea17a72f0 Merge branch 'obsd-master' 2018-08-29 11:02:36 +01:00
nicm
f57aa143c1 Keep any text killed in the command prompt with C-w and yank it with
C-y, only use the top buffer if no text has previously been killed. This
and previous change promped by discussion with kn@.
2018-08-29 09:50:32 +00:00
nicm
e53094bc5f Add C-Left and C-Right as aliases for M-b and M-f. 2018-08-29 08:56:51 +00:00
Thomas Adam
18b611bc8d Merge branch 'obsd-master' 2018-08-27 13:02:38 +01:00
nicm
79d2351ce8 Memory leaks, from Gang Fan in GitHub issue 1453. 2018-08-27 11:03:34 +00:00
Nicholas Marriott
79a9472dbc tty_clamp_* need to use wp->xoff and wp->yoff for the check (which
don't include status line, line ox and oy), but ctx->xoff and yp->off
to calculate the position (which do have the statu line).
2018-08-26 14:10:39 +01:00
Thomas Adam
d64daf874f Merge branch 'obsd-master' 2018-08-26 11:02:38 +01:00
nicm
1b4402c823 Add q: format prefix to escape sh(1) special characters. Suggested by
someone ages ago and then more recently in GitHub issue 1449.
2018-08-26 09:28:42 +00:00
Nicholas Marriott
7fbd2f5498 Do not draw cells which have no cell (zoomed and they are not active). 2018-08-25 13:55:50 +01:00
Thomas Adam
45841400f2 Merge branch 'obsd-master' 2018-08-23 21:02:36 +01:00
nicm
f38b5a1b58 all_jobs can be static. 2018-08-23 18:39:12 +00:00
Thomas Adam
da5d563375 Merge branch 'obsd-master' 2018-08-23 19:02:40 +01:00
nicm
bceccc6b63 Move job struct into job.c. 2018-08-23 15:45:05 +00:00
Nicholas Marriott
183193bdbc Update CHANGES. 2018-08-23 08:52:22 +01:00
Thomas Adam
5b93f0fcd3 Merge branch 'obsd-master' 2018-08-22 23:02:43 +01:00
Nicholas Marriott
ee3e0eb183 Update TODO. 2018-08-22 21:29:30 +01:00
nicm
55db3623bf Add StatusLeft and StatusRight mouse key modifiers for the left and
right parts of the status line.
2018-08-22 20:06:14 +00:00
Nicholas Marriott
db8849e7ca Update TODO. 2018-08-21 09:29:12 +01:00
Nicholas Marriott
bfc9fb4b3b Add flags to refresh-client (-U -D -L -R and -c) to pan a window that
is larger than the client manually. Bound to S-Up, S-Down, S-Left,
S-Right and Delete manually.

Also add aliases for keys DC = Delete, IC = Insert, and make
refresh-client -C accept XxY as well as X,Y to match default-size.
2018-08-21 09:27:19 +01:00
Nicholas Marriott
314ee137a9 The stored mouse position should not include the status line offset if any. 2018-08-21 09:10:23 +01:00
Thomas Adam
f36d2ecb07 Merge branch 'obsd-master' 2018-08-20 23:02:38 +01:00
nicm
98a478ceb3 Move offset of window list into status struct. 2018-08-20 20:41:58 +00:00
Nicholas Marriott
9f39470b38 Only screen-redraw.c needs to adjust for message or prompt when the
status line is off, get rid of tty_status_lines and just pass the
client into status_line_size so it can check the CLIENT_STATUSOFF flag
as well.
2018-08-20 20:05:34 +01:00
Nicholas Marriott
458b4b7701 Need to adjust for lines if at top. 2018-08-20 19:45:32 +01:00
Nicholas Marriott
31508228bc Use the y offset from the context which has already been adjusted for
the status line, also make tty_clamp_line adjust the y position.
2018-08-20 19:34:04 +01:00
Nicholas Marriott
1e8c9fb490 Update CHANGES. 2018-08-20 17:52:27 +01:00
Thomas Adam
098967a085 Merge branch 'obsd-master' 2018-08-20 17:02:39 +01:00
nicm
665f046950 Add -Z to find-window as well. 2018-08-20 15:00:42 +00:00
Nicholas Marriott
641191ab20 Support for windows larger than the client.
This adds two new options, window-size and default-size, and a new
command, resize-window.

The force-width and force-height options, and the session_width and
session_height formats have been removed.

The new window-size option tells tmux how to work out the size of
windows: largest means it picks the size of the largest session,
smallest the smallest session (similar to the old behaviour) and
manual means that it does not automatically resize
windows. aggressive-resize modifies the choice of session for largest
and smallest as it did before.

If a window is in a session attached to a client that is too small,
only part of the window is shown. tmux attempts to keep the cursor
visible, so the part of the window displayed is changed as the cursor
moves (with a small delay, to try and avoid excess redrawing when
applications redraw status lines or similar that are not currently
visible).

Drawing windows which are larger than the client is not as efficient
as those which fit, particularly when the cursor moves, so it is
recommended to avoid using this on slow machines or networks (set
window-size to smallest or manual).

The resize-window command can be used to resize a window manually. If
it is used, the window-size option is automatically set to manual for
the window (undo this with "setw -u window-size"). resize-window works
in a similar way to resize-pane (-U -D -L -R -x -y flags) but also has
-a and -A flags. -a sets the window to the size of the smallest client
(what it would be if window-size was smallest) and -A the largest.

For the same behaviour as force-width or force-height, use
resize-width -x or -y.

If the global window-size option is set to manual, the default-size
option is used for new windows. If -x or -y is used with new-session,
that sets the default-size option for the new session.

The maximum size of a window is 10000x10000. But expect applications
to complain and higher memory use if you make a window that big. The
minimum size is the size required for the current layout including
borders.

This change allows some code improvements, most notably that since
windows can now never be cropped, that code can be removed from the
layout code, and since panes can now never be outside the size of the
window, window_pane_visible can be removed.
2018-08-20 15:22:14 +01:00
nicm
9f2db6a0af Fix problems with page scrolling in copy mode, GitHub issue 1440 from
Amos Bird.
2018-08-20 13:51:09 +00:00
Thomas Adam
bf03197e18 Merge branch 'obsd-master' 2018-08-19 21:40:26 +01:00
nicm
cac4eadca0 Add a flag to force redrawing of the status line even if the content
hasn't changed, needed for resizing.
2018-08-19 20:13:07 +00:00
Thomas Adam
3310972d75 Merge branch 'obsd-master' 2018-08-19 21:02:37 +01:00
nicm
d95fad3d5f Expand \u and \U escape sequences in command strings, from Christopher
Hunt in GitHub issue 1443.
2018-08-19 19:03:46 +00:00
Thomas Adam
9ecf657703 Merge branch 'obsd-master' 2018-08-19 19:02:40 +01:00
nicm
88327c7698 Add a client redraw-window flag instead of the redraw-all flag and for
all just use the three flags together (window, borders, status).
2018-08-19 16:45:03 +00:00
Thomas Adam
e811132b05 Merge branch 'obsd-master' 2018-08-18 23:02:40 +01:00
nicm
bd2896b65e SESSION_UNATTACHED flag is no longer necessary now we have an attached
count instead.
2018-08-18 20:08:52 +00:00
Thomas Adam
522d751eee Merge branch 'obsd-master' 2018-08-18 19:02:39 +01:00
nicm
3bc08b0dc0 Some tidying and helper functions. 2018-08-18 16:14:03 +00:00
Nicholas Marriott
af679326b2 Now master again. 2018-08-17 11:46:08 +01:00
Nicholas Marriott
aa6e6fa0f2 2.8. 2018-08-17 11:45:40 +01:00
Nicholas Marriott
9bdbe171b7 2.8-rc. 2018-08-17 11:31:16 +01:00
Thomas Adam
98a3c98c28 Merge branch 'obsd-master' 2018-08-17 11:20:20 +01:00
Nicholas Marriott
de2ddddd60 Add a full stop. 2018-08-17 10:30:04 +01:00
nicm
a9ffb56b65 Add the KEYC_XTERM flag to all function keys that imply a modifier so
that they are correctly translated into xterm(1)-style keys. GitHub
issue 1437.
2018-08-16 14:04:03 +00:00
nicm
14b97fc889 Add size to arguments struct too. 2018-08-14 11:38:05 +00:00
nicm
d0a600ccaa Some tidying, use a struct for arguments (there will be more later) and
add a helper function.
2018-08-14 11:31:34 +00:00
Thomas Adam
a368548645 Merge branch 'obsd-master' 2018-08-10 11:41:07 +01:00
Nicholas Marriott
13fe06a459 Update CHANGES. 2018-08-10 10:21:40 +01:00
nicm
87e87030fe Whoops, didn't mean to commit this. 2018-08-09 09:54:22 +00:00
nicm
a5ef1f2ed6 Bump the UTF-8 character array up to 18 to allow for more combining
characters (some languages use up to five). This size doesn't make as
much difference now that UTF-8 goes into an extended cell. GitHub issue
1430.
2018-08-09 09:53:44 +00:00
nicm
f5d7a80272 calloc the mode data instead of malloc and initialize everything. 2018-08-05 08:59:30 +00:00
Thomas Adam
33f9b316a3 Merge branch 'obsd-master' 2018-08-02 21:02:25 +01:00
nicm
d6ff630498 Log command arguments. 2018-08-02 18:35:21 +00:00
Thomas Adam
eceaa9a493 Merge branch 'obsd-master' 2018-08-02 15:02:25 +01:00
Thomas Adam
2e19a5ecb9 Merge branch 'obsd-master' 2018-08-02 13:02:26 +01:00
nicm
fb1f0fee5a session_groups can be static also. 2018-08-02 11:56:12 +00:00
nicm
6048b0f483 Make key trees and some other bits static. 2018-08-02 11:44:07 +00:00
nicm
f12b857415 Minor tidying. 2018-08-02 11:18:34 +00:00
Thomas Adam
79bdca4638 Merge branch 'obsd-master' 2018-08-02 11:02:25 +01:00
nicm
21f8ac2766 Make display-panes block the client until a pane is chosen or it times out. 2018-08-02 07:55:16 +00:00
Thomas Adam
89b56c3451 Merge branch 'obsd-master' 2018-08-01 17:02:25 +01:00
nicm
fe7486d43b Initialize new lineflag member. 2018-08-01 15:22:40 +00:00
Thomas Adam
400b807d75 Merge branch 'obsd-master' 2018-07-31 17:02:31 +01:00
nicm
5f07da6227 Do not leak path or use it after free. 2018-07-31 13:06:44 +00:00
Thomas Adam
7eb3ef66e5 Merge branch 'obsd-master' 2018-07-31 13:02:25 +01:00
nicm
82776c456e Move struct screen_sel into screen.c and tidy up members that are only
used by copy mode.
2018-07-31 11:49:26 +00:00
nicm
80bdd89856 Clear history on RIS like most other terminals do. 2018-07-31 10:32:19 +00:00
Thomas Adam
ed6327c87b Merge branch 'obsd-master' 2018-07-30 13:02:25 +01:00
nicm
b21a710de7 Remove a leftover unused struct. 2018-07-30 11:24:55 +00:00
Thomas Adam
aa32457772 Merge branch 'obsd-master' 2018-07-23 21:02:25 +01:00
kn
5c78b48cdf Point to glob in section 7 for the actual list of special characters instead
the C API in section 3.

OK millert jmc nicm, "the right idea" deraadt
2018-07-23 19:02:49 +00:00
Thomas Adam
5fc2d4a4fc Merge branch 'obsd-master' 2018-07-17 21:02:24 +01:00
nicm
969af935f3 When a key isn't in the first table, we need to try the same key again
not the any key. Also rename some labels. Fixes GitHub issue 1406
reeported by Mark Kelly.
2018-07-17 18:02:40 +00:00
Thomas Adam
4f04b2094c Merge branch 'obsd-master' 2018-07-16 11:02:25 +01:00
nicm
0d88f8a78b Add an "Any" key to run a command if a key is pressed that is not bound
in the current key table. GitHub issue 1404.
2018-07-16 08:48:22 +00:00
Thomas Adam
6de991d855 Merge branch 'obsd-master' 2018-07-15 11:02:25 +01:00
nicm
ff67ef945d Fix new-window -k, GitHub issue 1403. 2018-07-15 06:57:13 +00:00
Thomas Adam
711b8164bb Merge branch 'obsd-master' 2018-07-11 11:02:26 +01:00
Nicholas Marriott
35985c0add Updates to CHANGES. 2018-07-11 09:51:18 +01:00
nicm
cfc81692e6 Expand formats in load-buffer and save-buffer. 2018-07-11 08:29:21 +00:00
Thomas Adam
a4a7c3c68d Merge branch 'obsd-master' 2018-07-11 09:02:25 +01:00
nicm
e7d53020b4 Helper function to shorten history. 2018-07-11 06:51:39 +00:00
nicm
03519021b9 Add function comments. 2018-07-11 06:43:45 +00:00
Thomas Adam
6f2698004e Merge branch 'obsd-master' 2018-07-06 09:02:24 +01:00
nicm
28a5bc8fae Add a rectangle_toggle format, from Hirokazu Hata. 2018-07-06 07:11:23 +00:00
Thomas Adam
20154f391e Merge branch 'obsd-master' 2018-07-04 15:02:25 +01:00
jmc
98c4291df2 whitespace needed between macro args and punctuation; 2018-07-04 13:27:32 +00:00
Nicholas Marriott
5c0ce192ed +README.ja. 2018-07-04 13:45:40 +01:00
nicm
cc743dc296 Add set-hook -R to run a hook immediately (useful to set multiple hooks
to the same thing).
2018-07-04 12:30:52 +00:00
nicm
d254293a6d Add pane focus hooks. 2018-07-04 12:25:26 +00:00
Thomas Adam
850c26dd46 Merge branch 'obsd-master' 2018-07-04 13:02:25 +01:00
Nicholas Marriott
db07f33886 Japanese README from Kohei Takada. 2018-07-04 10:47:14 +01:00
nicm
2fae6a5761 Add accessors for grid linedata member, for some future work. From Dan
Aloni.
2018-07-04 09:44:07 +00:00
Thomas Adam
2ee0962c96 Merge branch 'obsd-master' 2018-07-02 15:02:25 +01:00
nicm
42935bde71 Fire notify for select-layout, from George Nachman. 2018-07-02 12:39:14 +00:00
Nicholas Marriott
ffebf00585 Solaris 11.4 and later prefers mdoc, from Alan Coopersmith. 2018-07-02 13:36:44 +01:00
Thomas Adam
ead6d652ff Merge branch 'obsd-master' 2018-06-27 19:02:25 +01:00
nicm
a14aa788d4 Allow any punctuation (except :) as separator in s/x/y/, not only
/. From JINNOUCHI Yasushi in GitHub issue 1386.
2018-06-27 17:36:10 +00:00
Thomas Adam
d8721b35a0 Merge branch 'obsd-master' 2018-06-26 15:02:25 +01:00
nicm
97738921cd Style nit. 2018-06-26 13:21:28 +00:00
Thomas Adam
486ce9b098 Merge branch 'obsd-master' 2018-06-26 13:02:25 +01:00
nicm
8fb6666f17 Do not take address of a member of a NULL pointer. GitHub issue 1382
from Kamil Rytarowski.
2018-06-26 11:14:05 +00:00
Thomas Adam
cb77c2aa78 Merge branch 'obsd-master' 2018-06-25 19:02:24 +01:00
nicm
0c94c3fbee If there are only two panes, always use the other pane as the last
pane. Based on a change from Duy Nguyen in GitHub issue 1377.
2018-06-25 17:23:16 +00:00
Thomas Adam
94712a8b0d Merge branch 'obsd-master' 2018-06-24 23:02:25 +01:00
nicm
dec6ec9e29 Minor cosmetic improvement from KOIE Hidetaka. 2018-06-24 21:24:09 +00:00
Thomas Adam
9da78d72de Merge branch 'obsd-master' 2018-06-11 13:02:25 +01:00
nicm
d0c992306d Fix some compiler warnings; from Thomas Adam. 2018-06-11 11:14:10 +00:00
Thomas Adam
54c2d48d7d Merge branch 'obsd-master' 2018-06-09 19:02:29 +01:00
nicm
e6cbeb4f38 Make it possible to resize multiple panes by dragging corners, from Dan
Aloni in GitHub issue 1376.
2018-06-09 17:05:52 +00:00
Thomas Adam
4581240ced Merge branch 'obsd-master' 2018-06-08 23:02:25 +01:00
nicm
f6bad7efd7 Instead of working out which pane to resize with the mouse by walking
the panes list, look through the layout cells for the nearest border and
resize that cell. From Dan Aloni in GitHub issue 1374.
2018-06-08 20:54:22 +00:00
Thomas Adam
713e0ddef3 Merge branch 'obsd-master' 2018-06-08 13:02:25 +01:00
nicm
ff45b2d343 Tweak previous - check for a NULL client and simplify manual text. 2018-06-08 09:43:58 +00:00
Thomas Adam
91280f1fca Linux: include sys/file.h for flock() 2018-06-07 09:17:05 +01:00
Thomas Adam
7de25d86e1 Merge branch 'obsd-master' 2018-06-03 13:02:31 +01:00
nicm
ba31d3a88c Increment the lines counter when skipping a line to avoid an infinite
loop, and fix a check to avoid a potential out-of-bounds access. Problem
reported by Yuxiang Qin and tracked down by Karl Beldan; GitHub issue
1352.

Also a man page fix request by jmc@.
2018-06-03 10:17:30 +00:00
Thomas Adam
54cd292f09 Merge branch 'obsd-master' 2018-05-29 11:02:26 +01:00
nicm
d1f5142dab If foo doesn't exist and can't be expanded in #{?foo,a,b} then assume it
is false.
2018-05-29 09:10:30 +00:00
Thomas Adam
058d2b94dc Merge branch 'obsd-master' 2018-05-28 15:02:31 +01:00
nicm
c177a627d2 When looking for panes, ignore dead ones (with -1 file
descriptor). GitHub issue 1354.
2018-05-28 11:50:47 +00:00
Nicholas Marriott
8f8e0975f1 Add format string test, from "sadie-parayno" in GitHub issue 1358. 2018-05-28 12:48:15 +01:00
nicm
b602c1fb9a Document escaping inside conditionals, from "sadie-parayno" in GitHub
issue 1359.
2018-05-28 11:45:26 +00:00
Thomas Adam
7448b38327 Merge branch 'obsd-master' 2018-05-24 13:02:29 +01:00
Thomas Adam
85d5a377c5 Merge branch 'obsd-master' 2018-05-24 11:02:25 +01:00
nicm
b9a6162d2f Make server_client_get_cwd used (almost) everywhere we need to work out
the cwd, and do not fall back to "." as it is pretty useless. GitHub
issue 1331.
2018-05-24 09:42:49 +00:00
nicm
8f5903d7c3 Improve logging of the environment etc for new panes. 2018-05-24 09:34:54 +00:00
Thomas Adam
f0ac0d6793 Merge branch 'obsd-master' 2018-05-22 11:02:33 +01:00
nicm
2a04665626 Allow escaping , and } with # in #{}; GitHub issue 1332. 2018-05-22 08:49:12 +00:00
Nicholas Marriott
07c0970f54 Sync tmux description with manual. 2018-05-22 08:02:43 +01:00
Thomas Adam
546123f950 Merge branch 'obsd-master' 2018-05-20 15:02:25 +01:00
nicm
f2f9605c63 -T should not actually select the pane. 2018-05-20 11:48:34 +00:00
Thomas Adam
e4e060f2be Merge branch 'obsd-master' 2018-05-15 17:02:31 +01:00
nicm
e3b034fac7 Fix switch-client -l, from Jean-Marc Eurin in GitHub issue 1343. 2018-05-15 14:58:09 +00:00
Thomas Adam
82c0eed36d Merge branch 'obsd-master' 2018-05-09 19:02:35 +01:00
nicm
80994a8de1 Mention allow-rename with \033k. 2018-05-09 16:20:50 +00:00
Thomas Adam
9e1093b7d7 Merge branch 'obsd-master' 2018-05-09 11:02:26 +01:00
nicm
f2029f9d9e Another check for NULL window if looking for index. 2018-05-09 07:50:03 +00:00
Thomas Adam
b2a2c3a1e9 Merge branch 'obsd-master' 2018-05-07 17:02:31 +01:00
nicm
f915a4bf0c Handle terminfo colors > 256 correctly, GitHub issue 1337. 2018-05-07 13:39:09 +00:00
Thomas Adam
91b220525b Merge branch 'obsd-master' 2018-05-04 11:02:31 +01:00
nicm
988c6bc433 Improve logging of sessions. 2018-05-04 08:21:42 +00:00
Thomas Adam
1d858aa89e Merge branch 'obsd-master' 2018-05-03 19:02:26 +01:00
nicm
e24a077752 Use window target if specified and exists even when looking for an
index, fixes neww -a with -t as well.
2018-05-03 16:56:59 +00:00
Thomas Adam
645fe9013f Merge branch 'obsd-master' 2018-04-26 17:02:31 +01:00
guenther
896c1da7da Use <fcntl.h> instead of <sys/file.h> for open() and friends.
Delete a bunch of unnecessary #includes and sort to match style(9)
while doing the above cleanup.

ok deraadt@ krw@
2018-04-26 12:42:51 +00:00
Thomas Adam
d24bd7394d Merge branch 'obsd-master' 2018-04-23 17:02:32 +01:00
Nicholas Marriott
aebb17dc75 Sync imsg from OpenBSD. 2018-04-23 15:40:15 +01:00
nicm
d9d2f84a4b Add KRB5CCNAME to update-environment. 2018-04-23 14:03:06 +00:00
nicm
068d1b97b2 #aabbcc will use RGB if supported so don't say it is closest match. 2018-04-23 13:51:21 +00:00
nicm
4bf6f2706e Check whether cursor is at start or end when copying rectangular
selections, from tb@.
2018-04-23 13:46:34 +00:00
nicm
9f39652d87 Remove unnecessary brackets. 2018-04-23 13:43:08 +00:00
Thomas Adam
c48440fd40 Merge branch 'obsd-master' 2018-04-23 11:02:27 +01:00
nicm
1afe71cc0a rxvt-unicode has some funny behaviour when scrolling with the cursor not
at column 1, so move it back there first if possible. GitHub issue 1318.
2018-04-23 07:41:30 +00:00
Thomas Adam
0e1b339c10 Merge branch 'obsd-master' 2018-04-18 17:02:28 +01:00
nicm
3dceddd70e Change how display-message uses the client. Originally it was only
intended as the target client where the message should be displayed but
at some point (perhaps when -p was added), it was used for format
expansion too. This means it can get a bit weird where you have client
formats expanding for a client with a different current session than the
target session.

However, it is nice that display-message can be used to show information
about a specific client. So change so that the -c client will be used if
the session matches the target session (-t or default), otherwise the
best client will be chosen.
2018-04-18 14:35:37 +00:00
nicm
2595718dd3 Include source function name in grid_check_y logging. 2018-04-18 14:31:42 +00:00
Thomas Adam
6ebd737590 Merge branch 'obsd-master' 2018-04-18 15:02:25 +01:00
nicm
e64d078a4c Fix || example. 2018-04-18 12:50:11 +00:00
Nicholas Marriott
ae0b7c7d72 Some changes. 2018-04-13 17:59:11 +01:00
Nicholas Marriott
a770ef3e2a Merge branch '2.7-rc' 2018-04-13 17:50:40 +01:00
Nicholas Marriott
b95d1de8fd 2.7. 2018-04-13 17:47:36 +01:00
Thomas Adam
7e5262ae9a Merge branch 'obsd-master' 2018-04-11 13:02:28 +01:00
nicm
14ecb5032e Allow no client for rename-session, from Ryan Freeman. 2018-04-11 09:54:45 +00:00
Thomas Adam
1bd66b65a3 Merge branch 'obsd-master' 2018-04-10 13:02:28 +01:00
nicm
051a29ca03 A couple of fixes to the : form of SGR. Apparently there is an extra
argument that nobody knew about, so skip that if it exists. Also there
are a bunch of useless optional arguments at the end, so ignore those.
2018-04-10 11:20:15 +00:00
nicm
c6975b3bb4 Add x and X to choose-tree (with a confirmation prompt) to kill an
item. Suggested by Matt Zagrabelny.
2018-04-10 10:48:44 +00:00
Nicholas Marriott
68bf7c532b Merge branch '2.7-rc' 2018-04-06 12:53:43 +01:00
Thomas Adam
9b73d76ddd Merge branch 'obsd-master' 2018-04-06 11:02:24 +01:00
nicm
5d616f4c72 Fix link, from Eliran Gonen. 2018-04-06 09:09:38 +00:00
nicm
8a81993ae1 Do not crash on empty window, reported by Jamie Macdonald in GitHub
issue 1299. Patch from Thomas Adam.
2018-03-29 13:19:19 +01:00
Thomas Adam
b5c0b2cae2 Merge branch 'obsd-master' 2018-03-29 10:28:18 +01:00
nicm
803b8815bd Do not crash on empty window, reported by Jamie Macdonald in GitHub
issue 1299. Patch from Thomas Adam.
2018-03-29 08:03:51 +00:00
nicm
785ce66ab9 Fix a regression: do not warn about no client in rename-window. 2018-03-26 07:39:12 +01:00
Thomas Adam
640d97afd0 Merge branch 'obsd-master' 2018-03-23 20:02:31 +00:00
nicm
194e9f611b Fix a regression: do not warn about no client in rename-window. 2018-03-23 19:17:03 +00:00
nicm
ea295ac397 Fix size calculation when spreading out panes. 2018-03-23 10:07:54 +00:00
Thomas Adam
5512de6a61 Merge branch 'obsd-master' 2018-03-23 10:02:30 +00:00
nicm
26792b9035 Fix size calculation when spreading out panes. 2018-03-23 07:44:44 +00:00
Nicholas Marriott
919f55ac4a Merge branch '2.7-rc' 2018-03-22 11:26:32 +00:00
Nicholas Marriott
2cd0ba5057 CHANGES for 2.7. 2018-03-22 11:25:58 +00:00
Nicholas Marriott
80283f99fb Revert "2.7-rc."
This reverts commit ced74bd72c.
2018-03-22 11:18:26 +00:00
Nicholas Marriott
ced74bd72c 2.7-rc. 2018-03-22 11:18:05 +00:00
Nicholas Marriott
50e3e3e72f Remove EVENT_* variables from environment after initializing libevent so they
are not carried into child processes; from Henry Qin.
2018-03-21 08:15:15 +00:00
Thomas Adam
c8a706117f Merge branch 'obsd-master' 2018-03-17 18:02:26 +00:00
nicm
0b3911631b Fix negative window index range check (> not <). Reported by Juan Pablo
in GitHub issue 1283.
2018-03-17 16:48:17 +00:00
Thomas Adam
0ca78ee51f Merge branch 'obsd-master' 2018-03-16 16:02:28 +00:00
nicm
f87d80737e Insert full size panes at the right position, from KOIE Hidetaka in
GitHub issue 1284.
2018-03-16 15:15:39 +00:00
Thomas Adam
9fd9952752 Merge branch 'obsd-master' 2018-03-08 10:02:26 +00:00
nicm
19f3a5c612 Add a missing client-detached hook when the server shuts down, and do
not exit until jobs started from run-shell/if-shell have finished (add a
job flags member and a flag to indicate other jobs). GitHub issue 1245.
2018-03-08 08:09:10 +00:00
Thomas Adam
3c451a64b5 Merge branch 'obsd-master' 2018-03-05 14:02:29 +00:00
nicm
85c48aafff For some reason tmux treats SGR 10 as SGR 0. It has done since the first
version and I'm not sure why since no other terminal appears to. Change
to just ignore SGR 10 instead.
2018-03-05 12:32:28 +00:00
Nicholas Marriott
61ea49c6dd Fix cmp use. 2018-03-02 15:08:34 +00:00
Thomas Adam
3b8f92359d Merge branch 'obsd-master' 2018-03-01 14:02:27 +00:00
nicm
182357f24b Expand formats in window and session names. 2018-03-01 12:53:08 +00:00
Thomas Adam
0ca9664ecf Merge branch 'obsd-master' 2018-02-28 10:02:29 +00:00
nicm
508e2f0b3a Add -Z flag to choose-tree, choose-client, choose-buffer to
automatically zoom the pane when the mode is entered and unzoom when it
exits, assuming the pane is not already zoomed. Add -Z to the default
key bindings.
2018-02-28 08:55:44 +00:00
Thomas Adam
f5a37d0071 Merge branch 'obsd-master' 2018-02-26 10:02:30 +00:00
nicm
4d72b8fff7 C-g for modes too, from Mike Hamrick. 2018-02-26 08:09:56 +00:00
Thomas Adam
9464b94f64 Merge branch 'obsd-master' 2018-02-22 14:02:30 +00:00
Thomas Adam
c2aa40449c Merge branch 'obsd-master' 2018-02-22 12:02:31 +00:00
nicm
3f3f13fbd7 Remove an unused variable. 2018-02-22 11:42:41 +00:00
nicm
e97daead43 Check prefix when retrying so it is checked while repeat flag is
set. GitHub issue 1239.
2018-02-22 10:58:12 +00:00
nicm
623f4b12d3 Add exit-empty option to exit server if no sessions (defaults to on). 2018-02-22 10:54:51 +00:00
Thomas Adam
5a44e18490 Merge branch 'obsd-master' 2018-02-20 12:02:23 +00:00
nicm
ab6f0bb348 Do not leak memory when working out job name in formats. 2018-02-20 10:43:46 +00:00
Thomas Adam
4e8b1b9ac2 Merge branch 'obsd-master' 2018-02-19 22:02:29 +00:00
Nicholas Marriott
d81aec2439 Update CHANGES. 2018-02-19 21:24:17 +00:00
nicm
6ae04dd5a0 Support ISO colon-separated SGR. 2018-02-19 21:20:10 +00:00
Thomas Adam
968296bb07 Merge branch 'obsd-master' 2018-02-16 12:02:29 +00:00
nicm
320abba341 Reflowing the grid in-place involved way too much memmove() for a big
performance cost with a large history. Instead change back to using a
second grid and copying modified lines over which is much faster (this
doesn't revert to the old code however which didn't support UTF-8
properly). GitHub issue 1249.
2018-02-16 09:51:41 +00:00
Thomas Adam
88711e885e Merge branch 'obsd-master' 2018-02-05 10:02:31 +00:00
nicm
7f4513ec34 Add struct status_line to hold status line members of struct client, not
used yet but will be soon. From Thomas Adam.
2018-02-05 08:21:54 +00:00
Thomas Adam
2d5101621b Merge branch 'obsd-master' 2018-02-05 08:02:27 +00:00
nicm
0817132f97 Show if filter is active/no matches in modes. 2018-02-05 06:51:41 +00:00
Thomas Adam
24abfb72eb Merge branch 'obsd-master' 2018-02-04 12:02:24 +00:00
nicm
fe7a871a23 Upstream ncurses has introduced terminfo capabilities to specify RGB
colour ("true" or "direct" colour). These consist of new entries (such
as "xterm-direct") which have a different setaf/setab implementation,
colors and pairs set to 0x1000000 and 0x10000, and a new RGB flag.

The setaf/setab definitions seem to be geared towards what ncurses (or
emacs maybe) needs, in that the new versions do only ANSI and RGB
colours (they can't be used for the 256 colour palette); they rely on
the silly ISO colon-separated version of SGR; and they use a weird
multiplication scheme so they still only need one argument. The higher
values of colors and pairs require a recent ncurses to parse.

tmux can use the RGB flag to detect RGB colour support (keeping the old
Tc extension for backwards compatibility for now). However, as we still
want to send 256 colour information unchanged when possible, the new
setaf/setab are awkward. So when RGB is present, reserve setaf/setab
only for ANSI colours and use the escape sequences directly for 256 and
RGB colours. (To my knowledge no recent terminal uses unusual escape
sequences for these in any case.)
2018-02-04 10:10:39 +00:00
Nicholas Marriott
4e4c500879 Add more to TODO. 2018-01-29 12:46:52 +00:00
Nicholas Marriott
0407d847a4 Add to TODO. 2018-01-29 12:44:31 +00:00
Thomas Adam
19afd842bf Merge branch 'obsd-master' 2018-01-18 16:02:25 +00:00
nicm
17d4c39f24 Discard all but the last line when reading from a #() command - the
callback is just going to be fired again straight away to go through all
the lines, it is better just to use the last one straight away.
2018-01-18 14:28:11 +00:00
Thomas Adam
d9e740f86d Merge branch 'obsd-master' 2018-01-18 08:02:30 +00:00
nicm
c9037fde1c Remove unused hooks_run function, from Thomas Adam. 2018-01-18 07:10:53 +00:00
Thomas Adam
84ddc72744 Merge branch 'obsd-master' 2018-01-17 11:26:10 +00:00
nicm
75842bfe66 Fix drawing of ACS characters (they need to go character-at-a-time),
accidentally broken in last commit.
2018-01-16 17:03:18 +00:00
nicm
5849b73b81 Add -I to pipe-pane to connect pane stdin as well as stdout, suggested
by Kristof Kovacs in GitHub issue 1186.
2018-01-16 09:00:38 +00:00
Nicholas Marriott
58e9d12f23 msys is apparently a cygwin variant that doesn't say it is cygwin... 2018-01-16 08:29:15 +00:00
nicm
53b25635da Another redundant check, GitHub issue 1219. 2018-01-15 15:30:03 +00:00
nicm
481703d669 Some unused code, GitHub issue 1219. 2018-01-15 15:27:03 +00:00
nicm
b0c1cefeda Do not collect top-bit-set characters in case they need to be replaced. 2018-01-12 16:43:47 +00:00
nicm
2c5a6f9af5 Simplify character replacement on non-UTF-8 terminals and make a common
function.
2018-01-12 16:41:00 +00:00
nicm
c03565611e Simplify UTF-8 states down into one state. 2018-01-12 16:32:12 +00:00
nicm
f32fd2df69 Improve error message if creating socket parent directory fails, from
Thomas Adam for GitHub issue 1215.
2018-01-12 10:22:02 +00:00
nicm
829fe38ab1 Improve logging for layout cells. 2018-01-12 10:16:03 +00:00
Thomas Adam
06684c93de Merge branch 'obsd-master' 2018-01-01 12:01:13 +00:00
nicm
d17c90583a Prefer PWD for current directory if present in client, from Wei Zhao in
GitHub issue 1183.
2018-01-01 11:19:08 +00:00
nicm
fe26f977e6 Add C-g at command prompt for emacs people, GitHub issue 1213. 2018-01-01 11:03:54 +00:00
Thomas Adam
6e99a2f4bb Merge branch 'obsd-master' 2017-12-31 22:01:15 +00:00
nicm
c9896d9554 Initialize the size of new panes created by the even-* layout correctly;
reported by Andreas Kahari and Anton Lindqvist.
2017-12-31 20:00:44 +00:00
Thomas Adam
ad417f6eb7 Merge branch 'obsd-master' 2017-12-28 14:01:14 +00:00
nicm
299c552e33 Redrawing status is needed after changing window flags or title does not
update if status line is off, GitHub issue 1191.
2017-12-28 12:10:50 +00:00
Thomas Adam
cd46568ebe Merge branch 'obsd-master' 2017-12-27 14:43:20 +00:00
nicm
937f8ed095 Draw command prompt correctly with status line off. 2017-12-27 13:55:42 +00:00
Nicholas Marriott
6ce8fe0537 Still need to globfree on failure. 2017-12-27 13:54:37 +00:00
nicm
c363c236aa Fix memory leak in screen_redraw_make_pane_status. 2017-12-22 23:16:41 +00:00
Thomas Adam
e19df0e869 Merge branch 'obsd-master' 2017-12-22 12:01:22 +00:00
nicm
7ba5ad4cfb Do not try to set default value on user options (they don't have one),
from Charles Howard in GitHub issue 1161.
2017-12-22 10:18:51 +00:00
nicm
5c82432200 Remove duplicate WheelUp/WheelDown entries in list, GitHub issue 1184. 2017-12-22 10:16:36 +00:00
Thomas Adam
74ecc866cf Merge branch 'obsd-master' 2017-12-19 16:01:20 +00:00
nicm
b20a00f93e Report better error from server when socket create fails, GitHub issue
1201.
2017-12-19 15:00:39 +00:00
Thomas Adam
641a885af8 Merge branch 'obsd-master' 2017-12-19 00:01:18 +00:00
nicm
62144b9f57 Do not try to put more in command message than will fit when sending
(the server will treat as a fatal error). GitHub issue 1200.
2017-12-18 22:13:36 +00:00
Thomas Adam
43a1294ed9 Merge branch 'obsd-master' 2017-12-18 14:01:18 +00:00
nicm
58f6456af7 Remove unused variable from Thomas Adam. 2017-12-18 12:39:34 +00:00
Thomas Adam
2c6af068d7 Merge branch 'obsd-master' 2017-11-17 12:01:17 +00:00
nicm
695dc5a153 Allow formats in selectp -T, from Thomas Adam. 2017-11-17 09:52:18 +00:00
Thomas Adam
5fddddbe21 Merge branch 'obsd-master' 2017-11-16 12:01:18 +00:00
nicm
e5ae9dd53d Add -and-cancel variants for scrolling commands to exit copy mode when
the bottom is reached, from Stephen Hicks.
2017-11-16 11:16:15 +00:00
Thomas Adam
102df8dc80 Merge branch 'obsd-master' 2017-11-15 22:01:22 +00:00
Nicholas Marriott
e58d16b2df Add to CHANGES. 2017-11-15 20:14:49 +00:00
Thomas Adam
e755ca37b3 Merge branch 'obsd-master' 2017-11-15 20:01:22 +00:00
nicm
3b649d2fcd Add a common function for spreading out cells and use it for the two
even layouts and to add a -E flag to select-layout to spread out cells
evenly without changing parent cells.
2017-11-15 19:59:27 +00:00
nicm
533a5719c5 Completely rewrite the reflow code to correctly handle double width
characters (previously they were not accounted for).
2017-11-15 19:21:24 +00:00
nicm
aeda2e5808 If there is a double width character at the very end of the line with
not enough room to draw it, just leave it out.
2017-11-15 19:18:57 +00:00
Thomas Adam
392da897ff Merge branch 'obsd-master' 2017-11-13 14:01:18 +00:00
nicm
d81fa579c3 When searching in copy mode, do not scroll if the result is already on
screen. GitHub issue 1150.
2017-11-13 11:49:11 +00:00
Thomas Adam
515da63d2b Merge branch 'obsd-master' 2017-11-10 00:01:19 +00:00
nicm
384736e955 If we successfully change the directory, set PWD too to give the shell a
hint in case of symlinks.
2017-11-09 23:02:13 +00:00
Thomas Adam
6f3b6c8d92 Merge branch 'obsd-master' 2017-11-03 18:01:21 +00:00
nicm
a2681ffcee Clear key properly if on space with nothing in it. 2017-11-03 17:11:20 +00:00
nicm
50a5f84cb4 Support mouse on preview in tree mode. 2017-11-03 17:02:33 +00:00
Thomas Adam
24c387206c Merge branch 'obsd-master' 2017-11-03 16:01:17 +00:00
nicm
ba93a647f1 Change mouse in modes so that one click moves the cursor and a double
click chooses the line.
2017-11-03 14:23:44 +00:00
Thomas Adam
e1606172dd Merge branch 'obsd-master' 2017-11-03 00:01:20 +00:00
Thomas Adam
c9ec33d0d0 Merge branch 'obsd-master' 2017-11-02 22:01:20 +00:00
nicm
43264dfbf4 Make the mode draw function use the parent screen directly rather than
its own to avoid copying twice.
2017-11-02 22:00:42 +00:00
nicm
8d37f699ad Add a "fast" version of screen_write_copy for tree mode that doesn't do
all the checks and selection and marking stuff needed for copy mode.
2017-11-02 21:29:17 +00:00
Thomas Adam
8c29f7413b Merge branch 'obsd-master' 2017-11-02 20:01:26 +00:00
nicm
17655e5ba6 Format for group list of "other sessions" is a bit weird, just list all
the sessions in the group.
2017-11-02 18:52:05 +00:00
nicm
95850e1aca Tweak previous slightly so that current session is chosen if it is in
the group rather than first.
2017-11-02 18:43:51 +00:00
nicm
c1f62f1fde Only show the first member of session groups in tree mode (-G flag
disables).
2017-11-02 18:27:35 +00:00
nicm
3887d95bca There is no point in reflowing panes which have not changed width. 2017-11-02 18:26:38 +00:00
Thomas Adam
cf782c4f54 Merge branch 'obsd-master' 2017-10-26 10:01:18 +01:00
nicm
e91e8a2a6c Fix crash exiting command prompt (from Alex Maese in GitHub issue 1139)
and a man page tweak from jmc.
2017-10-26 08:17:12 +00:00
Thomas Adam
d36ac3db15 Merge branch 'obsd-master' 2017-10-25 18:01:17 +01:00
nicm
be4c01697c Note that notifications are also hooks. 2017-10-25 15:20:10 +00:00
Thomas Adam
0072bc65e6 Merge branch 'obsd-master' 2017-10-25 16:01:22 +01:00
Nicholas Marriott
37f83adca8 Update CHANGES. 2017-10-25 15:26:54 +01:00
nicm
578a63bbc9 Default allow-rename to off because it is ridiculous that applications
are even able to do this and confusing when they do.
2017-10-25 14:14:52 +00:00
Thomas Adam
6b83ca0077 Merge branch 'obsd-master' 2017-10-25 14:01:26 +01:00
nicm
78ae4ee82c h/l keys for expand and collapse. 2017-10-25 12:13:20 +00:00
Nicholas Marriott
d6edd06749 Merge branch 'master' of github.com:tmux/tmux 2017-10-25 12:29:23 +01:00
Nicholas Marriott
6e8d29e9a2 Update TODO. 2017-10-25 12:29:10 +01:00
nicm
8dd776106d Add P key to paste tagged in buffer mode, and trim some code that should
no longer be necessary.
2017-10-25 11:26:11 +00:00
Thomas Adam
e85213a944 Merge branch 'obsd-master' 2017-10-22 15:47:07 +01:00
nicm
26f1857154 Use window_pane_index() when drawing pane numbers (so pane-base-index is
applied), from Thomas Adam. GitHub issue 1125.
2017-10-22 13:16:54 +00:00
Nicholas Marriott
f7a037ba26 Apparently vim(1) now has syntax highlighting built in, GitHub issue 1124. 2017-10-22 14:14:14 +01:00
Thomas Adam
61114c6c72 Merge branch 'obsd-master' 2017-10-20 16:01:17 +01:00
nicm
d3e8709ab5 Clear status line with spaces again so reverse works, spotted by sthen. 2017-10-20 13:10:54 +00:00
Nicholas Marriott
37531673a3 Need compat for queue.h. 2017-10-20 13:26:54 +01:00
Thomas Adam
31901e3c07 Merge branch 'obsd-master'
Conflicts:
	server-fn.c
2017-10-20 12:36:29 +01:00
Nicholas Marriott
a34de2e378 Save and restore LIBS when checking for b64_ntop, reported by Ralf Friedl. 2017-10-17 10:35:35 +01:00
nicm
2f6935a630 Infrastructure for drawing status lines of more than one line in height,
still only one is allowed but this lets tmux draw bigger ones.
2017-10-16 19:30:53 +00:00
nicm
a5fd5782f8 Show exit status and time in the remain-on-exit pane text, mostly from
Timo Boettcher in GitHub issue 1103.
2017-10-12 11:32:27 +00:00
Nicholas Marriott
fb02df66cc Merge branch 'master' of github.com:tmux/tmux 2017-10-12 11:56:32 +01:00
Nicholas Marriott
d10def5b0b Check missed during merge. 2017-10-12 11:56:06 +01:00
Thomas Adam
2357bfb254 Merge branch 'obsd-master' 2017-10-11 16:01:17 +01:00
Thomas Adam
87babfa473 Merge branch 'obsd-master' 2017-10-11 14:01:17 +01:00
nicm
eb9839fd32 Box around label in preview. 2017-10-11 12:57:49 +00:00
nicm
6e5121be7e Clear to end of line properly with UTF-8 present. 2017-10-11 11:26:58 +00:00
Thomas Adam
4efd41f3af Merge branch 'obsd-master' 2017-10-11 10:01:19 +01:00
nicm
99351c9cae Add C-n and C-p keys for tree mode, and choose the right initial line
when no panes.
2017-10-11 08:08:16 +00:00
Nicholas Marriott
60074a6bc6 Merge branch 'master' of github.com:tmux/tmux 2017-10-11 08:03:55 +01:00
Nicholas Marriott
a3967de9a5 Include headers if found regardless of forkpty. 2017-10-11 08:03:31 +01:00
Thomas Adam
044019d9d6 Merge branch 'obsd-master' 2017-10-09 14:01:16 +01:00
nicm
db44151a37 kind should be S-Down not S-Up. 2017-10-09 11:35:35 +00:00
Thomas Adam
ceab7154d4 Merge branch 'obsd-master' 2017-10-08 18:40:41 +01:00
nicm
0b4c408168 Fix description of history_size, from Campbell Barton. 2017-10-08 16:45:01 +00:00
Thomas Adam
f069c0ba09 Merge branch 'obsd-master' 2017-10-06 20:01:17 +01:00
nicm
9c4caf49a2 Support %else in config files to match %if, from Brad Town in GitHub
issue 1071.
2017-10-06 18:02:30 +00:00
Thomas Adam
2be01ab4ec Merge branch 'obsd-master' 2017-10-06 13:33:32 +01:00
nicm
b462063cd5 Add -- to some key bindings so leading -s work. 2017-10-05 13:43:34 +00:00
Nicholas Marriott
8aaf86a6ea Merge branch '2.6-rc' 2017-10-05 14:39:33 +01:00
Nicholas Marriott
bd71cbbe27 2.6. 2017-10-05 14:31:23 +01:00
nicm
88517ceebb Add support for the xterm(1) title stack, from Brad Town, GitHub issue
1075.
2017-10-05 13:29:18 +00:00
nicm
6a292f09ba When writing batches of characters to the screen, we need to clear
padding or later UTF-8 characters could be displayed incorrectly. GitHub
issue 1090.
2017-10-05 08:12:24 +00:00
nicm
71ec616e4d Initialize alerts timer event where it is used, avoids crash with new windows. 2017-09-22 17:58:30 +01:00
Thomas Adam
ff526e43de Merge branch 'obsd-master' 2017-09-22 12:01:13 +01:00
nicm
d563aa7c7b Initialize alerts timer event where it is used, avoids crash with new windows. 2017-09-22 09:04:46 +00:00
Thomas Adam
ae5a62a514 Merge branch 'obsd-master' 2017-09-13 10:01:10 +01:00
nicm
c86d83f835 Remove unused (always 1) arguments from some functions, from Daniel
Mueller in GitHub issue 1073.
2017-09-13 07:31:07 +00:00
Thomas Adam
9a1b9f15a1 Merge branch 'obsd-master' 2017-09-11 22:01:10 +01:00
nicm
af2c7ce646 Check event is initialized before delete; fixes crash reported by
Michael Nickerson in GitHub issue 1068.
2017-09-11 20:11:45 +00:00
Nicholas Marriott
b541a97821 2.6-rc3. 2017-09-11 10:12:25 +01:00
Nicholas Marriott
a8b84b7cfa 2.6-rc3. 2017-09-11 10:08:28 +01:00
Nicholas Marriott
495e2ed17f Merge branch 'master' into 2.6-rc 2017-09-11 10:08:15 +01:00
Thomas Adam
d8c397d1b7 Merge branch 'obsd-master' 2017-09-11 10:01:11 +01:00
nicm
d8d6c2746e Mention that filter is a format. 2017-09-11 06:53:06 +00:00
nicm
6fdaaa0637 Do not free more lines than are available in the history. 2017-09-11 06:40:46 +00:00
Nicholas Marriott
034b19b734 2.6-rc2. 2017-09-10 16:08:22 +01:00
Nicholas Marriott
cb8eba1530 Merge branch 'master' into 2.6-rc 2017-09-10 16:07:44 +01:00
Thomas Adam
7aa8b8a25c Merge branch 'obsd-master' 2017-09-10 16:01:14 +01:00
Nicholas Marriott
abcbfcb0e8 Merge branch 'master' into 2.6-rc 2017-09-10 15:38:02 +01:00
nicm
70bc07a358 Previously, extended cell data was never reduced in size even when the
cell was overwritten. With a large history this can be a substantial
amount of memory. To reduce this, compact each extended cell list to
only cells in use as it is scrolled off the visible screen into the
history. From Dan Aloni in GitHub issue 1062.
2017-09-10 14:36:12 +00:00
Thomas Adam
7f83b53027 Merge branch 'obsd-master'
Conflicts:
	server-client.c
2017-09-10 11:39:45 +01:00
nicm
8405fcdd9b Apply timeout to CAN and RS which also wait for ST. 2017-09-10 08:01:23 +00:00
nicm
f56f09ea38 Fix a few errors in how the selected line is chosen after resize,
reported by Felix Rosencrantz in GitHub issue 1059.
2017-09-08 16:28:41 +00:00
Nicholas Marriott
c62cfe64c8 Add to CHANGES. 2017-09-08 14:22:34 +01:00
nicm
78cf3c14ca When removing a key table clear it out of clients, fixes issue with
unbind -a reported by Thomas Sattler.
2017-09-08 08:45:27 +00:00
nicm
89e057dc4a Do not fail if unset an option that is already unset, reported by Thomas
Sattler.
2017-09-07 13:18:44 +00:00
nicm
466066c3a1 Do not attempt to use TIOCSWINSZ on a -1 file descriptor (possible if
the pane has already died).
2017-09-06 07:12:41 +00:00
Thomas Adam
ff3d05d92f Merge branch 'obsd-master' 2017-09-04 12:01:11 +01:00
nicm
eadd79acec Move to current mouse position not last when clcking in copy mode; fixes
GitHub issue 1055. Also a man page fix from jmc.
2017-09-04 09:18:51 +00:00
Thomas Adam
d019821281 Merge branch 'obsd-master' 2017-09-02 20:01:18 +01:00
nicm
f4848b437f Add selectp -T to set pane title. 2017-09-02 17:51:54 +00:00
Nicholas Marriott
e941e532fa Mention GitHub for code. 2017-08-30 21:49:31 +01:00
Nicholas Marriott
a1986c5973 Add to CHANGES. 2017-08-30 21:24:16 +01:00
Nicholas Marriott
6e2b3f435a Add to CHANGES. 2017-08-30 21:23:26 +01:00
Nicholas Marriott
07d3c4d882 Merge branch 'master' into 2.6-rc 2017-08-30 20:04:37 +01:00
Thomas Adam
f81e87f1e2 Merge branch 'obsd-master' 2017-08-30 20:01:11 +01:00
nicm
6abfd9b8ff Instead of overloading the line clear function to mean free if
background is default (8), introduce an explicit free function and use
it where a free alone is needed. Likewise, use memmove directly rather
than grid_move_lines where it makes sense. Based on a memory leak fix by
Dan Aloni in GitHub issue 1051.
2017-08-30 18:13:47 +00:00
Nicholas Marriott
07c679b52d Merge branch 'master' into 2.6-rc 2017-08-30 12:04:09 +01:00
Nicholas Marriott
b4c633cc40 Merge branch 'master' of github.com:tmux/tmux 2017-08-30 12:03:59 +01:00
Thomas Adam
54c5070767 Merge branch 'obsd-master' 2017-08-30 12:01:10 +01:00
nicm
17cf1b21c6 Pass flags into cmd_find_from_* to fix prefer-unattached, reported by
Thomas Sattler.
2017-08-30 10:33:57 +00:00
Nicholas Marriott
8f364053ca Add to TODO. 2017-08-30 11:21:20 +01:00
Nicholas Marriott
2e4e521629 2.6-rc version. 2017-08-30 09:34:27 +01:00
Nicholas Marriott
fa20f19494 Fix position of -v, pointed out by Thomas Sattler. 2017-08-30 09:33:53 +01:00
Nicholas Marriott
c1d8b0f74e Back to master. 2017-08-29 22:19:46 +01:00
Nicholas Marriott
3815e4f05e This is not true now... 2017-08-29 22:19:27 +01:00
Nicholas Marriott
72488b526b Merge branch 'master' into 2.6-rc 2017-08-29 22:06:22 +01:00
Nicholas Marriott
5fec6c598e Merge branch 'master' of github.com:tmux/tmux 2017-08-29 22:06:06 +01:00
Thomas Adam
dee6bb5a31 Merge branch 'obsd-master' 2017-08-29 22:01:11 +01:00
Nicholas Marriott
566b9623b3 Merge branch 'master' into 2.6-rc 2017-08-29 21:42:15 +01:00
Nicholas Marriott
3f3fb43850 More style. 2017-08-29 21:42:05 +01:00
Nicholas Marriott
2248b886fe 2.6-rc version. 2017-08-29 21:37:51 +01:00
Nicholas Marriott
82b30f2322 Style of headings. 2017-08-29 21:34:56 +01:00
Nicholas Marriott
6b841a036a Fix example from Adam Spiers. 2017-08-29 21:32:09 +01:00
nicm
a7d1ee5433 Redraw rectangle selections properly when cursor at end, GitHub issue 992. 2017-08-29 20:26:25 +00:00
Thomas Adam
0f7160eb2f Merge branch 'obsd-master' 2017-08-29 12:01:25 +01:00
Nicholas Marriott
91d6bff8b8 Merge branch 'master' of github.com:tmux/tmux 2017-08-29 11:13:54 +01:00
Nicholas Marriott
5cdccf78a1 Update CHANGES. 2017-08-29 11:13:35 +01:00
nicm
5fc0be5045 Support REP escape sequence (\033[b). 2017-08-29 09:28:45 +00:00
nicm
9852bd743c Check for complete keys before escape prefix, allows keys to be defined
with a leading escape. GitHub issue 1048.
2017-08-29 09:18:48 +00:00
Thomas Adam
7d3bf6453e Merge branch 'obsd-master' 2017-08-28 14:01:17 +01:00
nicm
fe4467ad2b Do not forbid targets to specify non-visible panes - the checks for
visibility are better where the target is used. GitHub issue 1049.
2017-08-28 12:36:38 +00:00
Thomas Adam
b2322b3893 Merge branch 'obsd-master' 2017-08-27 11:48:44 +01:00
nicm
fccfc4e4be Do not allow the current line of screen when the preview is toggled,
from Thomas Adam.
2017-08-27 09:08:36 +00:00
Thomas Adam
e65cc09276 Merge branch 'obsd-master' 2017-08-27 10:01:15 +01:00
nicm
25cf126de8 Use kind and kri for S-Up/Down as well as kUP and kDN. 2017-08-27 08:33:55 +00:00
Thomas Adam
1492c9d7d9 Merge branch 'obsd-master' 2017-08-24 12:01:10 +01:00
nicm
3c63ad4a9c When tty is error or closed, remove client. Reported by Thomas Sattler. 2017-08-24 08:48:37 +00:00
Thomas Adam
3b40f8e42c Merge branch 'obsd-master' 2017-08-23 12:01:13 +01:00
nicm
08b125194e Key (v) and flag (-N) to toggle preview in choose modes. 2017-08-23 09:39:11 +00:00
nicm
1d60dd5872 Fix searching when match is at end of line, from Brad Town. 2017-08-23 09:18:22 +00:00
nicm
f0ce29c341 Allow multiple bells even if there is an existing bell (but not activity
or silence), from Brad Town.
2017-08-23 09:16:39 +00:00
nicm
e1b3dc89d2 Run alert hooks based on the options rather than unconditionally, from
Brad Town.
2017-08-23 09:14:21 +00:00
Nicholas Marriott
0f708dd6e2 Add to TODO. 2017-08-22 13:02:20 +01:00
Thomas Adam
730312e60f Merge branch 'obsd-master' 2017-08-22 00:01:10 +01:00
nicm
bbe9da063e Same as previous for \r alone. 2017-08-21 21:02:58 +00:00
nicm
7ec2a2b9ce Do not emit \r\n to move to column 0 if there are margins, because it
will instead move to the margin left.
2017-08-21 21:01:21 +00:00
Thomas Adam
ccdc369025 Merge branch 'obsd-master' 2017-08-20 00:01:22 +01:00
nicm
768740ae98 Fix example for user-keys. 2017-08-19 20:40:16 +00:00
Thomas Adam
07a13697e1 Merge branch 'obsd-master' 2017-08-17 12:01:17 +01:00
nicm
8daa1d5f54 Add monitor-bell window option to match the activity and silence
options, from Brad Town.
2017-08-17 08:37:38 +00:00
Nicholas Marriott
de86bf1856 Add to CHANGES. 2017-08-16 16:23:58 +01:00
Thomas Adam
2103a09430 Merge branch 'obsd-master' 2017-08-16 14:01:15 +01:00
nicm
c6a8ad23a1 Add -d flag to display-panes to specify timeout, and make 0 mean no
timeout. From Laurens Post.
2017-08-16 12:12:54 +00:00
nicm
c1ec28a34b Rename BELL_* values to ALERT_* now they are used by more than bells,
based on a diff from Brad Town.
2017-08-16 11:46:08 +00:00
Thomas Adam
0824850bbc Merge branch 'obsd-master' 2017-08-09 16:01:10 +01:00
Thomas Adam
27c3852103 Merge branch 'obsd-master'
Conflicts:
	tmux.1
2017-08-09 15:07:18 +01:00
nicm
ac2ba0961b Fix filtering so it works after the change to only show windows if they
have multiple panes.
2017-08-09 13:44:36 +00:00
Nicholas Marriott
237b7a50f4 Update CHANGES and TODO. 2017-08-09 12:48:54 +01:00
nicm
5dd5543fe4 Add -F to choose-tree, choose-client, choose-buffer to specify the
format of each line, as well as adding a couple of formats needed for
the default display.
2017-08-09 11:43:45 +00:00
Thomas Adam
4bb5bb9450 Merge branch 'obsd-master' 2017-08-08 12:01:15 +01:00
nicm
31b06571aa Hooks for after-select-pane and after-select-window. 2017-08-08 09:21:20 +00:00
Thomas Adam
e7b1e05bbd Merge branch 'obsd-master' 2017-08-02 14:01:10 +01:00
nicm
6f9b9655d7 Add selection_present format so commands in copy mode can use it, GitHub
issue 1028.
2017-08-02 11:10:48 +00:00
Nicholas Marriott
45ee118b26 Merge branch 'master' of github.com:tmux/tmux 2017-07-28 15:14:35 +01:00
Nicholas Marriott
0d6fc7eb1e I already mentioned these... revert previous. 2017-07-28 15:14:01 +01:00
Thomas Adam
ed8ddf2449 Merge branch 'obsd-master' 2017-07-28 14:01:13 +01:00
nicm
b4c9f6edba Show pane title in window list for windows with only one pane. 2017-07-28 10:59:58 +00:00
Nicholas Marriott
a704f57971 This is a big meaningless. 2017-07-27 23:25:39 +01:00
Nicholas Marriott
6b60a5c6d6 Update CHANGES. 2017-07-27 23:22:54 +01:00
Thomas Adam
147740ed40 Merge branch 'obsd-master' 2017-07-27 14:01:13 +01:00
nicm
3df7c91f1a Add pane_at_left/right/top/bottom formats, from Amos Bird. 2017-07-27 10:42:05 +00:00
Thomas Adam
58744de3eb Merge branch 'obsd-master' 2017-07-26 18:01:16 +01:00
nicm
b1bd0c7fc1 Always reset the alerts timer so it works even if activity and silence
are enabled on the same window.
2017-07-26 16:16:25 +00:00
nicm
76887b1d27 Make bell, activity and silence alerting more consistent:
- remove the bell-on-alert option;

- add activity-action and silence-action options with the same possible
  values as the existing bell-action;

- add "both" value for the visual-bell, visual-activity and
  visual-silence options to trigger both a bell and a message.

This means all three work the same way. Based on changes from Yvain Thonnart.
2017-07-26 16:14:08 +00:00
Nicholas Marriott
06a2644ab2 Update CHANGES. 2017-07-26 11:25:33 +01:00
Nicholas Marriott
ef9afddd1a Merge branch 'master' of github.com:tmux/tmux 2017-07-26 08:41:45 +01:00
Nicholas Marriott
3065b21375 Mention autoconf and automake. 2017-07-26 08:38:37 +01:00
Thomas Adam
358df10191 Merge branch 'obsd-master' 2017-07-22 02:01:13 +01:00
nicm
3bb426d92c Use the actual width written rather than the possible width to clear. 2017-07-21 22:55:45 +00:00
Thomas Adam
26db50d6df Merge branch 'obsd-master' 2017-07-21 16:01:13 +01:00
nicm
8c6ad55320 Trim trailing spaces from full line when it is clearly OK to do so. 2017-07-21 14:25:29 +00:00
nicm
e0d49ad758 Allow ispunct() as well as isalnum() when parsing initial window names. 2017-07-21 12:58:02 +00:00
Thomas Adam
e725b96a59 Merge branch 'obsd-master' 2017-07-21 12:01:16 +01:00
nicm
11e2af6df7 Add -c for respawn-pane and respawn-window, from J Raynor. 2017-07-21 09:17:19 +00:00
Thomas Adam
acbbc93501 Merge branch 'obsd-master' 2017-07-14 22:01:10 +01:00
nicm
932f6cfbfc Because ignore SIGCHLD early, letting signal_del restore it doesn't work
correctly, so set it explicitly back to default (and the others for good
measure).
2017-07-14 18:49:07 +00:00
Thomas Adam
1265e212e4 Merge branch 'obsd-master' 2017-07-14 10:01:11 +01:00
Nicholas Marriott
e4cd8751a2 Update CHANGES. 2017-07-14 09:14:23 +01:00
nicm
2678fe53f5 Fix redraw defer code in the presence of multiple clients - the timer
may be needed for all of them, so don't delete it on the first; and
don't skip setting the redraw flag if the timer is already running.

Reported by Pol Van Aubel in GitHub issue 1003.
2017-07-14 08:04:23 +00:00
Thomas Adam
e3698e6e1f Merge branch 'obsd-master' 2017-07-12 16:01:11 +01:00
nicm
8b84fc177c Line up keys in tree mode, and don't expand windows with one pane. From
Thomas Adam.
2017-07-12 14:31:06 +00:00
Thomas Adam
5122f3477f Merge branch 'obsd-master' 2017-07-12 14:01:13 +01:00
Thomas Adam
1076a2e26c Merge branch 'obsd-master'
Conflicts:
	cmd-pipe-pane.c
	proc.c
	tmux.c
	window.c
2017-07-12 13:43:08 +01:00
nicm
fba6140a4a Do not need to set up USR2 twice. 2017-07-12 12:35:31 +00:00
nicm
51112221ee Block signals between forking and clearing signal handlers (or calling
event_reinit) - if the child gets a signal and fires the libevent signal
handler during this period it could write a signal into the parent's
signal pipe. GitHub issue 1001 from Aaron van Geffen.
2017-07-12 10:04:51 +00:00
nicm
0453ad0146 Move signal code into proc.c. 2017-07-12 09:24:17 +00:00
nicm
ed3cfaafb2 Make shell_command a global like other stuff rather than making it an
exception and using callback argument.
2017-07-12 09:21:25 +00:00
nicm
d0d42dc4cb proc_send_s now seems unnecessary. 2017-07-12 09:07:52 +00:00
Thomas Adam
fbbf5a108b Merge branch 'obsd-master' 2017-07-10 00:01:15 +01:00
nicm
58b796608f Some extra logging to show why tmux might exit. 2017-07-09 22:33:09 +00:00
Thomas Adam
05062e7d2d Merge branch 'obsd-master' 2017-07-07 18:01:15 +01:00
nicm
bfaa885f10 Fix size of rightmost preview section. 2017-07-07 16:27:26 +00:00
nicm
9913cce3ba Add a pane_pipe format to show if pipe-pane is active, GitHub issue 990. 2017-07-07 14:39:45 +00:00
Thomas Adam
1029f2b277 Merge branch 'obsd-master' 2017-07-07 10:01:09 +01:00
nicm
1f7ca973c5 When working out the current client (for example for switch-client with
no target), prefer clients attached to the current session if there is
one. GitHub issue 995 from Jan Larres.
2017-07-07 07:13:14 +00:00
Thomas Adam
6b1ceca86a Merge branch 'obsd-master' 2017-07-05 00:01:10 +01:00
nicm
53d4ed22e8 < and > keys to scroll preview list left and right in tree mode. 2017-07-04 22:21:31 +00:00
Thomas Adam
feb044bd2d Merge branch 'obsd-master' 2017-07-04 14:01:15 +01:00
nicm
bedf8bd437 Handle 0 size of preview box in caller. 2017-07-04 12:26:14 +00:00
Thomas Adam
6cb4a3bb19 Merge branch 'obsd-master' 2017-07-04 02:01:13 +01:00
nicm
4039802fce Change session and window preview so that the current window or pane is
always shown.
2017-07-03 22:48:02 +00:00
Thomas Adam
5e98770936 Merge branch 'obsd-master' 2017-07-03 16:01:14 +01:00
nicm
6ee0afb579 Change previous to not wait for both process exit and pty close -
instead if there is a pipe-pane active, do not exit until all data is
read (including any libevent hasn't seen yet). Fixes problem reported by
Theo Buehler and still seems to solve the original issue.
2017-07-03 12:38:50 +00:00
Thomas Adam
4e01036cb6 Merge branch 'obsd-master' 2017-07-03 10:01:14 +01:00
nicm
28687f2d55 Do not close panes until process has exited and any outstanding data
has been written to the pipe-pane event if there is one. GitHub issue 991.
2017-07-03 08:16:03 +00:00
nicm
42285ac989 Try C.UTF-8 which is also a commonly useful locale on some platforms,
from Romain Francoise.
2017-07-03 08:08:30 +00:00
Thomas Adam
6fba9a39b7 Merge branch 'obsd-master' 2017-07-01 00:01:21 +01:00
nicm
fa677fc0e1 Don't write over right border. 2017-06-30 22:37:35 +00:00
nicm
b565644c81 Fix previous when we end up able to show no panes. 2017-06-30 22:36:11 +00:00
nicm
7247553c77 Try to show a better preview of sessions and windows in tree mode. 2017-06-30 22:24:08 +00:00
Thomas Adam
f059fe3ef2 Merge branch 'obsd-master' 2017-06-30 00:01:14 +01:00
nicm
8b0fd63ddb Use 100 as the example for command-alias because the defaults are from 0
to (currently) 5.
2017-06-29 22:02:19 +00:00
Thomas Adam
336beeb09a Merge branch 'obsd-master' 2017-06-28 14:01:13 +01:00
nicm
a00b0d13ed Apply the xterm key flag when needed for send-keys, fixes problem
reported by Franky Spamschleuder.
2017-06-28 11:36:39 +00:00
Thomas Adam
1ca920bbeb Merge branch 'obsd-master' 2017-06-28 10:01:16 +01:00
nicm
1e376be13d Fix visual-silence (check accidentally the wrong way round), from Brad
Town. Plus some tmux.1 fixes from jmc@.
2017-06-28 06:45:31 +00:00
Thomas Adam
6995497e5b Merge branch 'obsd-master' 2017-06-23 18:01:11 +01:00
nicm
95ed7d48c8 Add user-keys option to allow user-defined keys to be set, from Dan
Aloni.
2017-06-23 15:36:52 +00:00
Thomas Adam
a61200776d Merge branch 'obsd-master' 2017-06-16 18:01:13 +01:00
nicm
a67df17763 Tweak some logging. 2017-06-16 15:12:38 +00:00
Thomas Adam
233bae6992 Merge branch 'obsd-master' 2017-06-16 14:01:14 +01:00
nicm
d685604d04 Log terminal capabilities for each new terminal. 2017-06-16 11:50:06 +00:00
Thomas Adam
91dec25fc9 Merge branch 'obsd-master' 2017-06-14 10:01:10 +01:00
nicm
af93453190 Don't overwrite error message when it is available in
cmd_string_parse. Reported by Jimi Damon in GitHub issue 975.
2017-06-14 07:42:41 +00:00
Nicholas Marriott
6e57401610 New test. 2017-06-14 08:37:58 +01:00
nicm
dec00d3579 Add missing error message when no target, GitHub issue 971. 2017-06-14 07:37:17 +00:00
Thomas Adam
154c95d0c9 Merge branch 'obsd-master' 2017-06-13 13:48:37 +01:00
nicm
ac7080b31b Remove xterm flag from key before checking prefix, reported by Peter
Fern in GitHub issue 974.
2017-06-13 07:12:33 +00:00
Thomas Adam
a073d11c3e Merge branch 'obsd-master' 2017-06-12 14:01:14 +01:00
nicm
e028ab3476 Need to flush out the linefeed after wrapper. GitHub issue 970. 2017-06-12 10:57:35 +00:00
Thomas Adam
5362f956f0 Merge branch 'obsd-master' 2017-06-12 10:01:15 +01:00
nicm
8037159f93 Add explicit keys for the bracketed paste sequences, both to avoid mix
ups with other keys and to make logs clearer.
2017-06-12 07:04:24 +00:00
Thomas Adam
4dbab75855 Merge branch 'obsd-master' 2017-06-09 18:01:14 +01:00
nicm
adcd5aff6f Extend filters (f key) to buffer and client mode and add -f flag to
specify to command.
2017-06-09 16:01:39 +00:00
nicm
bab4da5133 Add -O option to choose-* to set initial sort order. 2017-06-09 15:29:15 +00:00
nicm
3ec28ceb9b Default sort for buffer mode should be time not name. 2017-06-09 15:17:20 +00:00
Thomas Adam
ed45052d6d Merge branch 'obsd-master' 2017-06-09 16:01:13 +01:00
Nicholas Marriott
411640c032 Merge branch 'master' of github.com:tmux/tmux 2017-06-09 15:57:13 +01:00
Nicholas Marriott
eea93638c6 Set AM_CFLAGS for ncurses libraries, reported by Peter Schow. 2017-06-09 15:56:50 +01:00
nicm
a2ca51c27a Use brackets around prompts which looks better and matches the other modes. 2017-06-09 14:00:46 +00:00
Thomas Adam
e640907d24 Merge branch 'obsd-master' 2017-06-09 12:01:17 +01:00
nicm
74b2deae1c Add a hook when the clipboard is set. 2017-06-09 09:21:24 +00:00
Nicholas Marriott
143ccd27b4 Add memmem to compat. 2017-06-09 08:53:58 +01:00
Nicholas Marriott
a4d2fa1b6d Update TODO. 2017-06-08 17:21:30 +01:00
Nicholas Marriott
065c360730 Typo. 2017-06-08 14:08:04 +01:00
Nicholas Marriott
738d9aece7 Note what to have for building Git. 2017-06-08 13:40:24 +01:00
Nicholas Marriott
8c38409aef Merge branch 'master' of github.com:tmux/tmux 2017-06-08 13:29:59 +01:00
Nicholas Marriott
61ed6425bd Move FAQ online and do not ship TODO. 2017-06-08 13:29:36 +01:00
Thomas Adam
6e8c93afdd Merge branch 'obsd-master' 2017-06-08 10:01:10 +01:00
nicm
8c4ae1c938 Add size to client descriptions in list, suggested by Greg Hurrell. 2017-06-08 07:48:04 +00:00
Thomas Adam
4aa02c3743 Merge branch 'obsd-master' 2017-06-07 18:01:13 +01:00
nicm
356fab7bcb Return 1 if name matches not 0, also fix some spaces. 2017-06-07 15:27:46 +00:00
Nicholas Marriott
9543f076fd Use osdep_get_name. 2017-06-07 16:21:01 +01:00
Thomas Adam
86d6666fe7 Merge branch 'obsd-master' 2017-06-07 16:01:10 +01:00
nicm
405cc337f3 Add simple searching (C-s and n) to the various choose modes: by name
for client and tree, and by name and content for buffer.
2017-06-07 14:37:30 +00:00
Nicholas Marriott
772dacc89b Tweak title. 2017-06-07 11:27:04 +01:00
Nicholas Marriott
696d2889f4 Mention U8, from Carles Cufi. 2017-06-07 11:19:04 +01:00
Nicholas Marriott
9316b9b57a Typo. 2017-06-07 11:15:36 +01:00
Nicholas Marriott
fb288ef9a7 Remove a bunch of out-of-date stuff from the FAQ or stuff that is documentation
for other programs.
2017-06-07 11:13:05 +01:00
Thomas Adam
7077980055 Merge branch 'obsd-master' 2017-06-06 18:01:13 +01:00
nicm
50b27c8c0d Continue and pass keys through if they are repeated keys, so that the
first key after a repeated key doesn't get lost.
2017-06-06 15:49:35 +00:00
nicm
bbc35b0b19 Do not pass a state into commands when fired on individual items in tree
mode, rely on the %% target substitution in the command for the chosen
pane and leave the default target as the current pane (where the mode
is). Otherwise, joinp and similar end up with -t and -s the
same. Reported by Jacob Niehus in GitHub issue 960.
2017-06-06 15:07:35 +00:00
nicm
d7280917da Delete input event when evbuffer_read() fails to avoid just spinning
around a dead file descriptor. Seems to fix a problem reported by Greg
Hurrell in GitHub issue 941.
2017-06-06 14:53:28 +00:00
Nicholas Marriott
78352fdd32 Add a small dance to daemon() to reattach tmux to the user's namespace (which
allows access to the clipboard) on OS X 10.10 and above.

Chis Johnsen has done much work on and documentation of this issue, the code is
copied (with some tweaks) from his reattach-to-user-namespace at:

    https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard

Tested by Enrico Ghirardi.

Will see how this goes, if it breaks stuff it might go away again.
2017-06-06 07:59:53 +01:00
Nicholas Marriott
63f8a2cb89 Merge branch 'master' of github.com:tmux/tmux 2017-06-05 12:02:10 +01:00
Nicholas Marriott
e1686c26dd Update CHANGES. 2017-06-05 12:01:58 +01:00
Thomas Adam
a999f6f876 Linux build fixes
Linux doesn't have vis.h
2017-06-05 12:00:52 +01:00
Thomas Adam
e62e17d046 Merge branch 'obsd-master'
Conflicts:
	tmux.1
	window.c
2017-06-05 11:59:38 +01:00
nicm
2f04108f3a Do not leak command, from David CARLIER. 2017-06-04 15:36:33 +00:00
Nicholas Marriott
1c83c0ebcd tparm() fix for Solaris. 2017-06-04 11:27:35 +01:00
Nicholas Marriott
8ec6c323b6 signal.h for utempter, from David CARLIER. 2017-06-04 11:23:48 +01:00
nicm
c5b7faaefc Add a timeout to prevent the sequences which wait for a specific
terminator (OSC, APC and DCS) waiting forever, which helps to avoid
garbage (cat /dev/random) locking up panes completely. This (and the
last commit) prompted by a discussion with theo.
2017-06-04 09:22:34 +00:00
nicm
467ece53e6 Remove unused variable. 2017-06-04 09:02:57 +00:00
nicm
8149bc3fa6 Be more strict about escape sequences that rename windows or set titles:
ignore any that not valid UTF-8 outright, and for good measure pass the
result through our UTF-8-aware vis(3).
2017-06-04 09:02:36 +00:00
nicm
adf5628087 Support SIGUSR2 to stop and start logging for an existing server. Also
we currently only have two log levels so just use -v and -vv rather than
-v and -vvvv, and clarify the man page entry for -v.
2017-06-04 08:25:57 +00:00
Nicholas Marriott
67cd496b39 Update CHANGES. 2017-06-04 09:09:31 +01:00
nicm
184039044a Typo/style; plus man page escaping from jmc. 2017-06-04 08:02:20 +00:00
Thomas Adam
757eb060cd Merge branch 'obsd-master' 2017-06-03 20:01:10 +01:00
nicm
3442066054 Make set-clipboard a three-state option so tmux itself can ignore the
sequencess.
2017-06-03 17:43:01 +00:00
Thomas Adam
80235d6fdd Merge branch 'obsd-master' 2017-06-03 10:01:10 +01:00
nicm
493a1846d0 Foreground colours with the bright attribute set need to use the bright
entries in the palette. GitHub issue 954.
2017-06-03 07:15:23 +00:00
Thomas Adam
73b9328c1f Merge branch 'obsd-master'
Conflicts:
	window-buffer.c
2017-06-01 18:29:36 +01:00
nicm
248aa54bfd Style and spacing nits. 2017-05-31 17:56:48 +00:00
nicm
70cc8f2c7e Shut up a warning. 2017-05-31 16:44:33 +00:00
Nicholas Marriott
92d86586b7 Update TODO. 2017-05-31 17:38:34 +01:00
Nicholas Marriott
a8e0363914 Add setrgbf setrgbb. 2017-05-31 17:22:43 +01:00
Nicholas Marriott
35008200bd Differences to OpenBSD. 2017-05-31 16:34:39 +01:00
Nicholas Marriott
113356c848 Build fixes. 2017-05-31 16:29:07 +01:00
nicm
b3d0ed4057 time.h here too. 2017-05-31 15:27:57 +00:00
nicm
61c0189bb1 Need time.h. 2017-05-31 15:26:41 +00:00
Thomas Adam
f17ecaa495 Merge branch 'obsd-master'
Conflicts:
	Makefile.am
	cfg.c
	server-client.c
2017-05-31 15:56:13 +01:00
Nicholas Marriott
9c4d0d454a Some changes that will appear when we sync up. 2017-05-31 13:56:07 +01:00
nicm
d60663ea86 Some applications like vi(1) and tmux until 10 minutes or so ago, do not
redraw on SIGWINCH if the size returns to the original size between the
original SIGWINCH and when they get around to calling TIOCGWINSZ. So use
the existing resize timer to introduce a small delay between the two
resizes.
2017-05-31 11:00:00 +00:00
nicm
ea6428a5d2 It is not OK to ignore SIGWINCH if SIOCGWINSZ reports the size has
unchanged, because it may have changed and changed back in the time
between us getting the signal and calling ioctl(). Always redraw when we
see SIGWINCH.
2017-05-31 10:29:15 +00:00
nicm
80c6b487dc Because we defer actually resizing applications (calling TIOCSWINSZ)
until the end of the server loop, tmux may have gone through several
internal resizes in between. This can be a problem if the final size is
the same as the initial size (what the application things it currently
is), because the application may choose not to redraw, assuming the
screen state is unchanged, when in fact tmux has thrown away parts of
the screen, assuming the application will redraw them.

To avoid this, do an extra resize if the new size is the same size as
the initial size. This should force the application to redraw when tmux
needs it to, while retaining the benefits of deferring (so we now resize
at most two times instead of at most one - and only two very rarely).

Fixes a problem with break-pane and zoomed panes reported by Michal
Mazurek.
2017-05-31 10:15:51 +00:00
nicm
7eb496c00c Look for setrgbf and setrgbb terminfo extensions for RGB colour. This is
the most reasonable of the various (some bizarre) suggestions for
capabilities.
2017-05-31 08:43:44 +00:00
nicm
aad4e4ddb1 Rewrite of choose mode, both to simplify and tidy the code and to add
some modern features.

Now the common code is in mode-tree.c, which provides an API used by the
three modes now separated into window-{buffer,client,tree}.c. Buffer
mode shows buffers, client mode clients and tree mode a tree of
sessions, windows and panes.

Each mode has a common set of key bindings plus a few that are specific
to the mode. Other changes are:

- each mode has a preview pane: for buffers this is the buffer content
  (very useful), for others it is a preview of the pane;

- items may be sorted in different ways ('O' key);

- multiple items may be tagged and an operation applied to all of them
  (for example, to delete multiple buffers at once);

- in tree mode a command may be run on the selected item (session,
  window, pane) or on tagged items (key ':');

- displayed items may be filtered in tree mode by using a format (this
  is used to implement find-window) (key 'f');

- the custom format (-F) for the display is no longer available;

- shortcut keys change from 0-9, a-z, A-Z which was always a bit weird
  with keys used for other uses to 0-9, M-a to M-z.

Now that the code is simpler, other improvements will come later.

Primary key bindings for each mode are documented under the commands in
the man page (choose-buffer, choose-client, choose-tree).

Parts written by Thomas Adam.
2017-05-30 21:44:59 +00:00
Thomas Adam
cea83c0e1f Merge branch 'obsd-master' 2017-05-30 10:01:12 +01:00
nicm
bd39fcbeea Preserve search string when entering prompt again. 2017-05-30 08:13:48 +00:00
Thomas Adam
0d073907b5 Merge branch 'obsd-master' 2017-05-30 00:01:14 +01:00
Thomas Adam
5ee6dc2120 Merge branch 'obsd-master' 2017-05-29 22:01:15 +01:00
nicm
64552ae304 Add a flag to stop the prompt input being expanded. 2017-05-29 20:42:53 +00:00
nicm
b95e5827c1 Store a copy of the old status line, will be needed soon for new choose mode. 2017-05-29 20:41:29 +00:00
nicm
8a214b2f8e Function to count clients. 2017-05-29 20:37:30 +00:00
Thomas Adam
5bc5fe5e7e Merge branch 'obsd-master' 2017-05-29 20:01:12 +01:00
nicm
a2ace9da24 Add ||, && format operators and C: to search pane content. 2017-05-29 18:06:34 +00:00
Thomas Adam
d3959a2118 Merge branch 'obsd-master' 2017-05-29 18:01:14 +01:00
nicm
1257501499 Add m: for fnmatch(3) format matching. 2017-05-29 15:43:48 +00:00
Thomas Adam
bfd7209053 Merge branch 'obsd-master' 2017-05-29 10:01:15 +01:00
nicm
1883d299bf Do not factor in screen_hsize() for the visible copy mode screen when
adjusting the selection, it should never have any useful history (and
when it does, after resize, we shouldn't use it). From Michal Mazurek.
2017-05-29 07:58:33 +00:00
nicm
15253448af Tweak text to mention initial size, from John Hood. 2017-05-29 07:46:32 +00:00
Nicholas Marriott
b017dc7e32 Update release text. 2017-05-29 08:40:33 +01:00
Nicholas Marriott
b5a6458cde Merge branch '2.5-rc' 2017-05-29 08:23:03 +01:00
Nicholas Marriott
caa90735cf 2.5. 2017-05-29 08:12:25 +01:00
Nicholas Marriott
de45957c42 Add to CHANGES. 2017-05-29 08:11:47 +01:00
Thomas Adam
f4a42738af Merge branch 'obsd-master' 2017-05-29 02:01:15 +01:00
nicm
d5158620bb Support OSC 10 and 11 to set foreground and background colours, from
"bertnp" in GitHub issue 942.
2017-05-28 23:23:40 +00:00
Nicholas Marriott
bf5a196c78 Changes in master. 2017-05-28 22:10:17 +01:00
Thomas Adam
5d7dfefa36 Merge branch 'obsd-master' 2017-05-28 22:01:11 +01:00
nicm
dbc8cae18c Change so that sessions created detached (-d or no client) are always
80x24 and the status line is not applied until they attach. Also make -x
and -y work for control clients whether the session is detached or not.
2017-05-28 19:46:55 +00:00
Nicholas Marriott
1e1e0f1fbb Add test for -x and -y too. 2017-05-28 20:15:45 +01:00
nicm
385bf084a5 Also recalculate session sizes when refreh-client -C is used. GitHub
issue 947.
2017-05-28 19:00:52 +00:00
Nicholas Marriott
eb1f362687 Do not need /dev/null. 2017-05-28 19:53:08 +01:00
Nicholas Marriott
5386e6583d Add some tests. 2017-05-28 19:52:51 +01:00
Thomas Adam
d1497527c6 Merge branch 'obsd-master' 2017-05-17 18:01:14 +01:00
nicm
91d202da7e Tidy command prompt callbacks and pass in the client. 2017-05-17 15:20:23 +00:00
Nicholas Marriott
3888bf9d12 Need to check libutil for fparseln. 2017-05-17 12:48:42 +01:00
Thomas Adam
3df4e78492 Merge branch 'obsd-master' 2017-05-16 16:01:28 +01:00
Nicholas Marriott
b74b6dc77f Missed during merge. 2017-05-16 14:15:35 +01:00
nicm
31625c2d17 Line length and spaces to tabs. 2017-05-16 12:57:26 +00:00
Thomas Adam
dcdaf5c8b9 Merge branch 'obsd-master' 2017-05-15 20:01:14 +01:00
Thomas Adam
36181775cd Merge branch 'obsd-master' 2017-05-15 18:01:14 +01:00
nicm
1ba7f1d03f Check the terminfo(5) U8 capability and disable using UTF-8 for ACS if
it is present and zero. This is useful for users with terminals or fonts
that do not correctly support UTF-8 line drawing characters. GitHub
issue 927, reported by Hiroaki Yamazoe and Akinori Hattori.
2017-05-15 16:44:04 +00:00
nicm
b160de5cb4 Notify layout changed when choosing predefined layouts, from Joshua Brot. 2017-05-15 14:57:29 +00:00
Thomas Adam
7edaedf3a1 Merge branch 'obsd-master' 2017-05-15 10:01:16 +01:00
nicm
cb5fcb3d22 The Konsole SU bug means it can't clear the entire scroll region (it
ignores if >= size, not if > as I first thought). So we can't
effectively fix it in code - remove the workarounds which just cause
bugs on other terminals.
2017-05-15 07:54:44 +00:00
Thomas Adam
58f8421eac Merge branch 'obsd-master' 2017-05-13 10:01:16 +01:00
nicm
7a4c66b7f5 Scroll the right number of lines off the region when clearing. 2017-05-13 07:41:59 +00:00
nicm
d58c3793d6 Some other unused variables. 2017-05-13 07:30:50 +00:00
Nicholas Marriott
ea190d862a Merge branch '2.5-rc' 2017-05-13 08:20:01 +01:00
Nicholas Marriott
0f26739c9f 2.5-rc2. 2017-05-13 08:17:01 +01:00
Nicholas Marriott
ae2c5ad768 Reset updated flag when restarting job so new output is detected, reported by
Gregory Pakosz in GitHub issue 922.
2017-05-13 08:16:11 +01:00
Thomas Adam
9f9f8c8e76 Merge branch 'obsd-master' 2017-05-13 02:01:13 +01:00
nicm
50f1f1dce9 Compare >= for columns not >. 2017-05-12 23:10:19 +00:00
nicm
0264ef094a Can scroll away full lines to clear them too. 2017-05-12 23:06:43 +00:00
nicm
f688653710 Remove an unused variable. 2017-05-12 22:43:15 +00:00
Thomas Adam
886d896098 Merge branch 'obsd-master' 2017-05-12 18:01:14 +01:00
Nicholas Marriott
8331000764 Merge branch '2.5-rc' 2017-05-12 16:18:31 +01:00
nicm
0cd74723e1 When expanding a line in order to clear it, we need to use the default
background colour - there may be portions that we do not want to clear
with the new background colour.
2017-05-12 15:18:13 +00:00
Nicholas Marriott
2bff5e7867 ECH needs to use background colour. 2017-05-12 16:16:16 +01:00
nicm
90f2a417af Need to clear tty context before using it. 2017-05-12 16:04:13 +01:00
nicm
7c07f5f640 Cannot rely on cursor position after DL and IL (some terminals move to
column 0, some do not).
2017-05-12 16:03:49 +01:00
Thomas Adam
20e30593a5 Merge branch 'obsd-master' 2017-05-12 16:01:14 +01:00
nicm
e2a18e2b37 Need to store bg for ECH. 2017-05-12 14:56:56 +00:00
nicm
da724fe1c0 Cannot rely on cursor position after DL and IL (some terminals move to
column 0, some do not).
2017-05-12 14:13:54 +00:00
nicm
ffd8beb6f6 Need to clear tty context before using it. 2017-05-12 13:29:05 +00:00
nicm
5d3cf2ff15 Only redraw single client, and tweak some logging. 2017-05-12 13:27:57 +00:00
Thomas Adam
7f813dcb6a Merge branch 'obsd-master' 2017-05-12 14:01:17 +01:00
nicm
18bab30792 Scrolling needs to use background colour. 2017-05-12 13:00:56 +00:00
nicm
60f7b05c0c Regions can't be smaller than 2 so don't try to clear them by scrolling if so. 2017-05-12 11:19:24 +00:00
nicm
7f626c8959 Can use INDN to clear regions with default background colour if margins
are supported.
2017-05-12 11:13:43 +00:00
nicm
886d50dcab ECH needs to use background colour. 2017-05-12 10:50:11 +00:00
nicm
7d3e2c83d4 Store copy mode search string in pane so search-again command works even
if you exit and reenter copy mode (it doesn't remember the position,
just the search string), suggested by espie@.
2017-05-12 10:45:38 +00:00
Nicholas Marriott
1cdc4568bd Merge branch '2.5-rc' 2017-05-11 23:28:56 +01:00
nicm
69df38f8d8 Clear to start of screen needs to use background colour. 2017-05-11 23:28:44 +01:00
nicm
5e30b81825 Need to redraw out to cellsize (total cells used in a line) rather than
cellused (only non-space cells) because there may be cells with a
nondefault background.
2017-05-11 23:28:22 +01:00
Thomas Adam
99582befc4 Merge branch 'obsd-master' 2017-05-11 14:01:10 +01:00
nicm
c0d3f204b0 Clear to start of screen needs to use background colour. 2017-05-11 11:39:30 +00:00
nicm
989cdca95f Need to redraw out to cellsize (total cells used in a line) rather than
cellused (only non-space cells) because there may be cells with a
nondefault background.
2017-05-11 11:38:49 +00:00
Thomas Adam
def8f852e3 Merge branch 'obsd-master' 2017-05-11 10:01:10 +01:00
nicm
349cdd6110 Make environ_log prefix take a format. 2017-05-11 07:34:54 +00:00
nicm
c54a5b3690 Change how we resolve which pane is dragging when there are multiple
options - choose the largest pane, which is more likely to be the one the
user wants to resize. Prompted by a report from Thomas Sattler.
2017-05-11 07:24:42 +00:00
Thomas Adam
6d961d672d Merge branch 'obsd-master' 2017-05-10 22:01:13 +01:00
Thomas Adam
247ec2ad88 Merge branch 'obsd-master' 2017-05-10 20:01:17 +01:00
nicm
8ab2753521 Move to the right cursor position before using spaces to clear. 2017-05-10 18:40:13 +00:00
nicm
2dc9bfd93a Prevent control clients from affecting the session size until they have
specified a size with refresh-client -C. Prompted by a different change
with the same purpose from George Nachman.
2017-05-10 16:48:36 +00:00
nicm
9dc6946ebf We can use ECH to clear sections of lines, so use it for internal panes
(that don't touch an edge). Move all the tty clear code into two common
functions rather than having the same bunch of checks everywhere.
2017-05-10 16:47:03 +00:00
Thomas Adam
0868512bbc Merge branch 'obsd-master' 2017-05-10 16:01:10 +01:00
nicm
b519551153 Expand formats in option names and add -F flag to do so in option values as well. 2017-05-10 13:05:41 +00:00
Thomas Adam
f8b3f1622d Merge branch 'obsd-master' 2017-05-10 14:01:11 +01:00
nicm
0e3c5ebe1a Insert copy mode bindings at the right place in the command queue. 2017-05-10 10:46:59 +00:00
Nicholas Marriott
daef51e038 Typo. 2017-05-09 23:18:48 +01:00
Nicholas Marriott
e82c42661b Back to master. 2017-05-09 23:11:01 +01:00
Nicholas Marriott
3a47dec424 Fix test. 2017-05-09 23:01:10 +01:00
Nicholas Marriott
7b17618890 2.5-rc and changes. 2017-05-09 22:53:36 +01:00
Nicholas Marriott
71bc255e6f Merge branch 'master' of github.com:tmux/tmux 2017-05-09 22:34:15 +01:00
Nicholas Marriott
8f990c573c Update TODO. 2017-05-09 22:33:39 +01:00
Thomas Adam
3f1d6102f3 Merge branch 'obsd-master' 2017-05-09 20:01:10 +01:00
nicm
3712b41aba If the target pane for send-keys in in a mode with a key table (that is,
copy mode), then look the key up in the table and fire any command
instead of delivering the key to the pane directly where it will be
ignored. This makes C-b C-b (send-prefix) work in copy mode again.
2017-05-09 17:56:55 +00:00
Thomas Adam
4bcb64f8c1 Merge branch 'obsd-master' 2017-05-09 15:44:33 +01:00
Thomas Adam
a651b08a2f Merge branch 'obsd-master'
Conflicts:
	format.c
2017-05-09 15:44:13 +01:00
nicm
3b35daacf7 If the current screen was complex enough, it was possible to make redraw
itself hit the "terminal can't keep up" check. To avoid this, record how
much data we send during redraw (we know we will be starting with 0) and
skip the check until it has been flushed. GitHub issue 912.
2017-05-09 13:04:36 +00:00
nicm
18f36906a9 Set current pane in rotate-window. 2017-05-09 11:00:48 +00:00
nicm
5fee4638e0 Add a format for the name of the pane's mode, lets it be used as a
conditional for key bindings.
2017-05-07 22:27:57 +00:00
nicm
d52f579fd5 Up to now, tmux sees \033\033[OA as M-Up and since we turned on
xterm-keys by default, generates \033[1;3A instead of
\033\033[OA. Unfortunately this confuses vi, which doesn't understand
xterm keys and now sees Escape+Up pressed within escape-time as Escape
followed by A.

The issue doesn't happen in xterm itself because it gets the keys from X
and can distinguish between a genuine M-Up and Escape+Up.

Because xterm can, tmux can too: xterm will give us \033[1;3A (that is,
kUP3) for a real M-Up and \033\033OA for Escape+Up - in fact, we can be
sure any \033 preceding an xterm key is a real Escape key press because
Meta would be part of the xterm key instead of a separate \033.

So change tmux to recognise both sequences as M-Up for its own purposes,
but generate the xterm version of M-Up only if it originally received
the xterm version from the terminal.

This means we will return to sending \033\033OA instead of the xterm key
for terminals that do not support xterm keys themselves, but there is no
practical way around this because they do not allow us to distinguish
between Escape+Up and M-Up. xterm style escape sequences are now the de
facto standard for these keys in any case.

Problem reported by jsing@ and subsequently by Cecile Tonglet in GitHub
issue 907.
2017-05-07 21:25:59 +00:00
nicm
2fef10b9ac Add some formats to look at the session window stack, suggested by Scott
ROCHFORD.
2017-05-05 11:59:47 +00:00
Thomas Adam
f3221941f2 Merge branch 'obsd-master' 2017-05-04 10:01:12 +01:00
nicm
d98d316903 Some new notifications, mainly for active pane and current window and
session:

    pane-mode-changed
    window-pane-changed
    client-session-changed
    session-window-changed

From Joshua Brot.
2017-05-04 07:16:43 +00:00
Thomas Adam
97ecb4f9d8 Merge branch 'obsd-master' 2017-05-03 08:01:14 +01:00
nicm
ca6a121e63 Add a format for the last search string in copy mode and fix the prompt
so it can work when in -I, suggested by Suraj N Kurapati.
2017-05-03 05:53:34 +00:00
Thomas Adam
e354b0e40f Merge branch 'obsd-master' 2017-05-01 14:01:14 +01:00
nicm
0ccfb61bb0 In order that people can use formats like #D in #() in the status line
and not have to wait for an update when they change pane, we allow
commands to run more than once a second if the expanded form
changes. Unfortunately this can mean them being run far too often
(pretty much continually) when multiple clients exist, because some
formats (including #D) will always differ between clients.

To avoid this, give each client its own tree of jobs which means that
the same command will be different instances for each client - similar
to how we have the tag to separate commands for different panes.

GitHub issue 889; test case reported by Paul Johnson.
2017-05-01 12:20:55 +00:00
Nicholas Marriott
4b39120d22 .NOTPARALLEL. 2017-04-30 13:55:32 +01:00
Nicholas Marriott
76950a6401 Add regress/Makefile. 2017-04-30 13:47:25 +01:00
Nicholas Marriott
909d962d3a Make example match reality; Greg Hurrell. 2017-04-30 08:27:23 +01:00
Nicholas Marriott
dde53cfde1 Add to TODO. 2017-04-30 08:23:14 +01:00
Thomas Adam
0adb60b3a6 Merge branch 'obsd-master' 2017-04-30 00:01:17 +01:00
nicm
a2dd7daf4e Fix UTF-8 combining characters in column 0, based on a diff from Keith
Winstein.
2017-04-29 21:27:46 +00:00
Thomas Adam
3a8e56b282 Merge branch 'obsd-master' 2017-04-28 22:01:18 +01:00
Nicholas Marriott
36202a63e9 Merge branch 'master' of github.com:tmux/tmux 2017-04-28 20:22:31 +01:00
Nicholas Marriott
abad809e7a Test that kill-session closes the panes (processes end up dead). 2017-04-28 20:22:01 +01:00
nicm
0f2f783584 Log what is happening with window and session reference counts much more
obviously.
2017-04-28 19:13:55 +00:00
nicm
bcd6b41674 Remove a reference from the right window when removing from a winlink's
list.
2017-04-28 19:12:15 +00:00
nicm
92053cb492 Do not put the window on the alerts queue and add a reference unless the
alert is enabled and we are actually going to add the alerts event.
2017-04-28 19:10:48 +00:00
Thomas Adam
14cb489a3b Merge branch 'obsd-master' 2017-04-28 20:01:14 +01:00
nicm
54e2205e54 Konsole incorrectly ignores SU (CSI S) if the parameter is bigger than
the scroll region, so clamp it. Reported by Moritz Bunkus.
2017-04-28 17:58:44 +00:00
Thomas Adam
99b0f48b2e Merge branch 'obsd-master' 2017-04-28 16:01:12 +01:00
nicm
c12711affd Default for xterm-keys was wrong, stop documenting it. 2017-04-28 13:39:59 +00:00
Nicholas Marriott
e4b4125310 source-file too. 2017-04-27 13:14:14 +01:00
Nicholas Marriott
6b2d850e54 Tests for some new session and new window bits. 2017-04-27 13:09:08 +01:00
Thomas Adam
0daeefefdb Merge branch 'obsd-master' 2017-04-25 20:01:11 +01:00
nicm
d520dae6ac Make full width panes try to play more nicely with terminal copy and
paste by avoiding explicit line wraps if we think the terminal will wrap
anyway.
2017-04-25 18:30:29 +00:00
nicm
03d01eabb5 When we write out the grid including escape sequences, an SGR 0 needs to
cause the colours to be written again. Also treat colours separately
from attributes so that RGB colours will work.
2017-04-25 18:20:51 +00:00
Thomas Adam
65d6278f88 Merge branch 'obsd-master' 2017-04-25 18:01:11 +01:00
nicm
c48d09ec88 Do not update TERM into config file parsing has finished. 2017-04-25 15:35:10 +00:00
nicm
4a51a9d9d5 Block the initial client if there is one until the configuration file
has finished loading.
2017-04-25 14:46:23 +00:00
Nicholas Marriott
b938212563 Another test. 2017-04-25 15:40:10 +01:00
Nicholas Marriott
accaff8ac0 Remove stuff from TODO. 2017-04-25 14:31:05 +01:00
Nicholas Marriott
45965fb020 And another test. 2017-04-25 14:30:58 +01:00
Thomas Adam
6ac39d5cdb Merge branch 'obsd-master' 2017-04-25 14:01:16 +01:00
Nicholas Marriott
9794c03537 And another. 2017-04-25 13:50:44 +01:00
Nicholas Marriott
1b221a56ea Try to start writing test scripts. 2017-04-25 13:37:03 +01:00
nicm
eb6fd6ff80 if-shell doesn't need to queue its error message into a callback, and in
fact it can't do so because the item it was working with will have been
freed. Reported by Daniel Hahler.
2017-04-25 11:49:35 +00:00
Thomas Adam
9d041d8e6c Merge branch 'obsd-master' 2017-04-23 20:01:13 +01:00
nicm
5172014668 Only use ED for clear screen if at the bottom, same as earlier fix to
clear end of screen.
2017-04-23 18:13:24 +00:00
Thomas Adam
b853054e71 Merge branch 'obsd-master' 2017-04-22 16:01:19 +01:00
Thomas Adam
a6a294c8f8 Merge branch 'obsd-master' 2017-04-22 14:01:15 +01:00
nicm
1e0eb914d9 Memory leak from David CARLIER. 2017-04-22 12:55:06 +00:00
nicm
ae1a6c2fc5 Do not need getopt.h. 2017-04-22 12:08:41 +00:00
Thomas Adam
e802b683ea Merge branch 'obsd-master' 2017-04-22 12:01:19 +01:00
nicm
55cd4c7bc7 Can't collect UTF-8 characters of more than one byte at the moment. 2017-04-22 10:30:56 +00:00
nicm
a4eaac359a new -A should use the session name. 2017-04-22 10:26:44 +00:00
nicm
ee45a8a149 Get rid of the extra layer of flags and cmd_prepare() and just store the
CMD_FIND_* flags in the cmd_entry and call it for the command. Commands
with special requirements call it themselves and update the target for
hooks to use.
2017-04-22 10:22:39 +00:00
Thomas Adam
b08e451c91 Merge branch 'obsd-master' 2017-04-22 10:01:51 +01:00
nicm
2c0f826c36 Mouse bindings and hooks set up an initial current state when running a
command. This is used for the session, window and pane for all commands
in the command sequence if there is no -t or -s.

However, using it for all commands in the command sequence means that if
the active pane or current session is changed, subsequent commands still
use the previous state. So make commands which explicitly change the
current state (such as neww and selectp) update it themselves for later
commands. Commands which may invalidate the state (like killp) are
already OK because an invalid state will be ignored.

Also fill in the current state for all key bindings rather than just the
mouse, so that any omissions are easier to spot.
2017-04-22 08:56:24 +00:00
nicm
bcab77e266 We need to collect UTF-8 characters so that width != 1 characters are
correctly flushed.
2017-04-22 08:33:28 +00:00
Thomas Adam
d8398af770 Merge branch 'obsd-master' 2017-04-22 08:01:54 +01:00
nicm
30348edc7c Fix if-shell without a client (so in the config file). Reported by Theo
Buehler.
2017-04-22 06:27:15 +00:00
nicm
59ff9b8128 Typo in example. 2017-04-22 06:15:22 +00:00
nicm
2c9bdd9e32 Memory leaks, from David CARLIER. 2017-04-22 06:13:30 +00:00
Thomas Adam
21240c1a8f Merge branch 'obsd-master' 2017-04-22 00:01:11 +01:00
nicm
c8ecbf38ab Log error properly when no current state, and some other minor tweaks. 2017-04-21 22:23:24 +00:00
nicm
194a121ef6 Make sure cmd_find_from_* clear the state if they fail. 2017-04-21 22:00:06 +00:00
nicm
8867951144 Rename a variable. 2017-04-21 21:02:26 +00:00
Thomas Adam
fd13731049 Merge branch 'obsd-master' 2017-04-21 22:01:14 +01:00
nicm
c68ceca8cd Clear shared state if not filling it in. 2017-04-21 20:34:05 +00:00
nicm
efaf4c16cf Make the cmd_find_* functions more obvious when looking for a client,
rather than having it inside other functions. Should be no change to the
way targets are resolved just yet.
2017-04-21 20:26:34 +00:00
nicm
2ad09ab5af Key needs to be initialized to zero now it has flags in it. 2017-04-21 19:33:07 +00:00
Thomas Adam
1f209ed030 Merge branch 'obsd-master' 2017-04-21 20:01:18 +01:00
nicm
3c876235cc Style nits and an unused struct. 2017-04-21 18:18:17 +00:00
nicm
afa4e3ed9c Add cmd_find_from_winlink_pane and use it in a couple of places, and
make functions that can't fail void.
2017-04-21 17:22:20 +00:00
Thomas Adam
c376c5a817 Merge branch 'obsd-master' 2017-04-21 18:01:11 +01:00
nicm
92a77e7654 It is annoying that the copy mode key table (or any other key table)
will suppress root key table bindings. So change to always check the
root table if no binding is found in the current table (whether it be
the prefix table from pressing the prefix or the copy mode table from a
pane).

A root key binding can be blocked by binding the key to a command that
does nothing (like send-keys with no arguments).

Problem reported by Thomas Sattler.
2017-04-21 16:04:18 +00:00
Thomas Adam
4612419c14 Merge branch 'obsd-master' 2017-04-21 16:01:18 +01:00
nicm
c799425069 More unnecessary arguments now winlink points back to session. 2017-04-21 14:09:44 +00:00
nicm
428be9803c History needs to be loaded after config parsing is done - now that
commands are queued, that's in cfg_done not after start_cfg finishes.
2017-04-21 14:04:54 +00:00
nicm
bba588752f Store state shared between multiple commands in the queue in a shared
structure.
2017-04-21 14:01:19 +00:00
nicm
311dad8c28 Do not run the config file in the context of the first client, instead
use no client like we did before. This means commands like new-session
won't try to attach if they are in the config file.
2017-04-21 13:15:43 +00:00
Thomas Adam
93062ad099 Fix after merge 2017-04-21 09:29:22 +01:00
Thomas Adam
22e594fcea Merge branch 'obsd-master'
Conflicts:
	Makefile.am
	pty.c
2017-04-21 09:25:07 +01:00
Nicholas Marriott
02580ac134 Typo; Daniel Hahler. 2017-04-21 06:49:38 +01:00
Nicholas Marriott
b723f50e65 Do not need getopt.h for getopt, from Eric N Vander Weele. 2017-04-20 20:35:11 +01:00
Nicholas Marriott
4a2e75fc8c Merge branch 'master' of github.com:tmux/tmux 2017-04-20 19:09:36 +01:00
Nicholas Marriott
9420758127 getptmfd() and fdforkpty() compat. 2017-04-20 19:09:07 +01:00
nicm
87997efe8d Use fdforkpty() instead of our own unwrapped versions. 2017-04-20 17:49:26 +00:00
Thomas Adam
69e0f28333 Merge branch 'obsd-master' 2017-04-20 18:01:12 +01:00
nicm
51a0dbb172 Only set up a current target for mouse key bindings. Fixes:
bind q select-pane -U \; resize-pane -Z

(There is still some possible weirdness with the way we do current
targets, it should probably be done in a different way at some point.)
2017-04-20 15:16:20 +00:00
Nicholas Marriott
7934e7a6b5 Notes on target resolution. 2017-04-20 15:40:28 +01:00
Nicholas Marriott
aebbb15fe2 Turn on debug if $VERSION is master rather than commenting and uncommenting. 2017-04-20 12:06:39 +01:00
Thomas Adam
48371216df Merge branch 'obsd-master' 2017-04-20 12:01:14 +01:00
Nicholas Marriott
e30f9dc1fa Merge tag '2.4'
Version 2.4.
2017-04-20 11:59:07 +01:00
Nicholas Marriott
f21cb71fbe Enter date of release. 2017-04-20 11:52:16 +01:00
Nicholas Marriott
990218739a Missing :. 2017-04-20 11:03:23 +01:00
Nicholas Marriott
e7c2f53f2a Changes to CHANGES. 2017-04-20 11:00:15 +01:00
nicm
21993105e5 Now that struct winlink has a session pointer, can remove some arguments. 2017-04-20 09:43:45 +00:00
Thomas Adam
9b2f02efbd Update CHANGES file 2017-04-20 10:39:16 +01:00
nicm
0f25ad3ca3 There is no real need for window_printable_flags to allocate, make it
return a buffer from the stack.
2017-04-20 09:39:07 +00:00
Nicholas Marriott
f9c7c50a93 Update TODO. 2017-04-20 10:20:42 +01:00
nicm
0b44ad99b5 If a #() command doesn't exit, use its most recent line of output (it
must be a full line). Don't let it redraw the status line more than once
a second.

Requested by someone about 10 years ago...
2017-04-20 09:20:22 +00:00
Nicholas Marriott
78d707dc83 Add to TODO. 2017-04-20 08:53:03 +01:00
nicm
b087483538 load_cfg returns < 0 on error, not != 0. Problem reported by Kaushal Modi. 2017-04-19 22:19:22 +01:00
Thomas Adam
3385159c94 Merge branch 'obsd-master' 2017-04-19 20:01:11 +01:00
nicm
f184c6f06c load_cfg returns < 0 on error, not != 0. Problem reported by Kaushal Modi. 2017-04-19 16:59:54 +00:00
Thomas Adam
5a551ac57f Merge branch 'obsd-master' 2017-04-19 16:01:14 +01:00
nicm
53fde21bb8 Add a suspend helper function, and do not allow detaching or suspending
while already doing so.
2017-04-19 14:00:28 +00:00
Nicholas Marriott
b946bf43f5 Version 2.4. 2017-04-19 13:51:49 +01:00
Nicholas Marriott
d64a815e8d Missed freezero. 2017-04-19 13:50:52 +01:00
nicm
689f4bfac2 Style nits and a missing cast. 2017-04-19 12:44:29 +00:00
Thomas Adam
85af9c9c9d Merge branch 'obsd-master' 2017-04-19 10:01:12 +01:00
Nicholas Marriott
95c38087db Missed freezero. 2017-04-19 07:58:45 +01:00
nicm
fa6deb5866 When the data we have buffered to write to a terminal grows beyond a
reasonable amount (currently width * height * 8 bytes), discard all
output to the terminal and start trying to redraw periodically
instead. Continue with this until the amount of data we are trying to
write falls to a low level again.

This helps to prevent tmux sitting on a huge buffer of data when there
are processes with fast output running inside tmux but the outside
terminal is slow.

A new client_discarded format holds the amount of data that has been
discarded due to this mechanism.

The three variables (when to start this, when to stop, and how often to
redraw) are basically "works for me" at the moment, this is going in to
see how it goes and if it causes problems for anyone else.
2017-04-19 06:52:27 +00:00
Thomas Adam
a71c262d5f Merge branch 'obsd-master' 2017-04-19 00:01:15 +01:00
nicm
f731ae4a2d Revert use of DECSLRM on iTerm2, it doesn't help as much as we throught,
and there are some question marks about it's support.
2017-04-18 21:41:42 +00:00
nicm
8c8ce08d79 On terminals without DECSLRM, when a pane that is less than the full
with of the terminal scrolls, tmux needs to redraw the entire pane. This
results in a large amount of output data which can cause slow terminals
to struggle, particularly when many lines are scrolled together quickly.

This can be reduced by only redrawing when tmux doesn't hold any
buffered data for the terminal. If a redraw is required and data is
buffered, the redraw is deferred until all that data is consumed (it is
checked after every event loop, a timer is used to ensure this happens
at some point). While a redraw is pending, no additional data will be
written to the terminal.

The redraw still happens, now it is just pushed back if it is possible
it would just add more data on top of a terminal that is already
behind. This both gives the terminal a chance to catch up, and allows
tmux to process more scrolling (that would require additional redraws)
in the meantime.

Helps with a problem reported by Greg Hurrell.
2017-04-18 20:37:49 +00:00
Thomas Adam
de4f817bd6 Merge branch 'obsd-master' 2017-04-18 20:01:12 +01:00
nicm
623e35f594 Detect iTerm2 and use DECSLRM for it as well. 2017-04-18 18:21:37 +00:00
Thomas Adam
a54309147d Merge branch 'obsd-master' 2017-04-18 18:01:17 +01:00
nicm
fb3c5efa50 Add a format for number of bytes writtent to client, useful for debugging. 2017-04-18 15:44:17 +00:00
nicm
aace1ead1e Do not check for BCE for a background colour that isn't needed, use
colour 8 instead.
2017-04-18 15:27:47 +00:00
Thomas Adam
0aa959d7a3 Merge branch 'obsd-master' 2017-04-18 16:01:18 +01:00
nicm
83ff1e9bd3 Include client name in key logging. 2017-04-18 13:34:04 +00:00
Thomas Adam
28833efb48 Merge branch 'obsd-master' 2017-04-17 10:01:13 +01:00
nicm
175d1854d4 Don't bother moving the cursor for empty lines. 2017-04-17 08:10:44 +00:00
nicm
7461c165b5 Remove a couple of redraw flags that no longer have any effect. 2017-04-17 06:40:32 +00:00
Thomas Adam
d912687be7 Merge branch 'obsd-master' 2017-04-16 22:01:19 +01:00
nicm
d566c780e5 Memory leak, from David CARLIER. 2017-04-16 20:33:46 +00:00
nicm
54bcaab70e Use EL1 to clear lines when redrawing the leftmost pane, rather than
spaces.
2017-04-16 20:32:14 +00:00
Nicholas Marriott
9583878a7b Accept NULL pointer. 2017-04-12 07:41:11 +01:00
Nicholas Marriott
d720a1487b Update imsg*.c from OpenBSD. 2017-04-11 11:51:25 +01:00
Thomas Adam
5f662d91db Merge branch 'obsd-master'
Conflicts:
	server-client.c
	tmux.1
2017-04-06 11:10:17 +01:00
nicm
94b71bcb64 Add Home and End for copy mode. 2017-04-05 12:14:18 +00:00
nicm
36882ec789 Try again to resolve problems with mistaking sessions for windows: now
do not look up windows as sessions (and panes as windows) when they are
qualified with a ':' or a '.'. So 'foo' as a window target will look for
windows and sessions called 'foo', but ':foo' will only look for
windows, and 'foo:' only for sessions. This means the common case of
using an unadorned session as a window target (send -tfoo) should
continue to work, but an explicit window will not get confused with a
session (send -t:foo).
2017-04-05 11:04:48 +00:00
nicm
9b28200578 Give each client a name. This defaults to the tty name as before but
falls back to an alternative if the tty name is not available. This is
clearer than overloading the client ttyname member and allows us to
remove the path stored in the tty struct, it should always be the same
as the client.
2017-04-05 10:49:46 +00:00
nicm
ab4a4b2ad0 cfg_file can be static. 2017-04-05 10:45:39 +00:00
Thomas Adam
05c97d7fe9 Merge branch 'obsd-master' 2017-03-25 14:01:12 +00:00
nicm
b9a4beb6e7 Write raw strings in one go rather than character at a time. 2017-03-24 14:45:00 +00:00
Nicholas Marriott
2d84ee9001 Merge branch 'master' of github.com:tmux/tmux 2017-03-24 10:06:22 +00:00
Nicholas Marriott
2e5664d2df Update imsg*.[ch] from OpenBSD, add some compat bits it needs and remove some
bits it doesn't.
2017-03-24 10:05:53 +00:00
Thomas Adam
1384525dc1 Merge branch 'obsd-master' 2017-03-24 08:01:13 +00:00
nicm
591b26e46f Show count of search results in copy mode. 2017-03-24 07:14:27 +00:00
Nicholas Marriott
e87d808594 Remove coverage and profile flags. 2017-03-22 21:59:43 +00:00
Nicholas Marriott
1cb8145dc5 Tweak some comments. 2017-03-22 21:29:07 +00:00
Nicholas Marriott
c57039bc3d Can shorten these by using LIBOBJ. 2017-03-22 19:22:32 +00:00
Nicholas Marriott
9c0520f2c5 Merge branch 'master' of github.com:tmux/tmux 2017-03-22 08:46:12 +00:00
Nicholas Marriott
c3dbbdaadf Bump automake and autoconf versions. 2017-03-22 08:45:53 +00:00
Thomas Adam
843e605b89 Merge branch 'obsd-master' 2017-03-22 08:01:17 +00:00
Nicholas Marriott
643813c6ed DEFS -> AM_CPPFLAGS. 2017-03-22 07:54:30 +00:00
Nicholas Marriott
223ed4a989 Should not need -D_POSIX_PTHREAD_SEMANTICS. 2017-03-22 07:49:27 +00:00
Nicholas Marriott
080080fa23 Use AC_USE_SYSTEM_EXTENSIONS and explicitly check for daemon() in headers. 2017-03-22 07:42:45 +00:00
nicm
df3ab87964 Add support for the strikethrough attribute (SGR 9), using the new smxx
terminfo capability. This means there are now nine attribute bits, so
anything above 0xff uses an extended cell.
2017-03-22 07:16:54 +00:00
Nicholas Marriott
3cc2486106 Merge branch 'master' of github.com:tmux/tmux 2017-03-21 21:38:03 +00:00
Nicholas Marriott
57cb6ef3a2 Add to TODO. 2017-03-21 21:28:37 +00:00
Thomas Adam
02ddd4ce70 Merge branch 'obsd-master' 2017-03-21 20:01:16 +00:00
Nicholas Marriott
b008a07ebb Do not test for term.h since we don't use the result. 2017-03-21 19:41:25 +00:00
nicm
04e17a7e11 Use uid_t for UID not u_int. 2017-03-21 19:28:03 +00:00
Nicholas Marriott
cd7550cdf1 Some __unused. 2017-03-21 19:27:18 +00:00
Nicholas Marriott
c2b53598ad Bad merge. 2017-03-21 14:48:44 +00:00
Thomas Adam
57b4d3d593 Merge branch 'obsd-master' 2017-03-21 12:01:14 +00:00
nicm
cdaa758340 Fix movement after select-line, from Omar Sandoval. 2017-03-21 09:51:00 +00:00
nicm
c916feaf29 Fix pane movement by direction (up, down, left, right) when
pane-border-status is set, from KOIE Hidetaka.
2017-03-21 09:49:10 +00:00
Thomas Adam
31ae09efa0 Merge branch 'obsd-master'
Conflicts:
	utf8.c
2017-03-20 13:45:18 +00:00
Nicholas Marriott
066575fd5a Add to TODO. 2017-03-20 11:50:54 +00:00
Nicholas Marriott
792455ce87 Tweak test for program_invocation_short_name. 2017-03-18 14:37:37 +00:00
Nicholas Marriott
4eec3270ec Clarify that release instructions will install. 2017-03-18 08:33:15 +00:00
Nicholas Marriott
640666fb36 Fix some warnings. 2017-03-17 14:55:33 +00:00
nicm
67d2335130 Fix a couple of argument types. 2017-03-17 14:51:41 +00:00
nicm
481e48d119 Add h and l for collapse and expand in choose mode with vi(1) keys, from
Gregory Pakosz.
2017-03-17 14:41:54 +00:00
Thomas Adam
1ea19245b3 Merge branch 'obsd-master' 2017-03-16 22:01:18 +00:00
nicm
b69efbdd30 Redraw after killp -a. 2017-03-16 20:05:14 +00:00
Thomas Adam
0dd694f5fd Merge branch 'obsd-master' 2017-03-15 16:01:13 +00:00
nicm
2a9d697771 Invalidate the cursor when we think we should have wrapped. 2017-03-15 15:22:14 +00:00
Thomas Adam
4e809a3130 Merge branch 'obsd-master' 2017-03-15 10:01:11 +00:00
nicm
3c3c08b6d9 Try to avoid moving the cursor to the start of the next line when
printing cells if it is already at the very end of the line and the
terminal will wrap it to the next line itself, this means terminals
still see it as a wrapped line for the purposes of their own mouse
selection. Reported by millert@.
2017-03-15 09:21:21 +00:00
Thomas Adam
cc6c6edb6f Merge branch 'obsd-master' 2017-03-13 18:01:13 +00:00
nicm
8e9b10062b Log where panes are created. 2017-03-13 17:20:11 +00:00
Thomas Adam
12c6c723a9 Merge branch 'obsd-master' 2017-03-13 12:01:13 +00:00
nicm
fd65210139 Revert previous, breaks normal short targets, reported by Theo Buehler. 2017-03-13 10:53:32 +00:00
Thomas Adam
266e662fae Merge branch 'obsd-master' 2017-03-11 16:01:12 +00:00
nicm
d455da45eb Fix calculation of size for full size splits. 2017-03-11 15:16:35 +00:00
nicm
0fe3b739a1 Only look for window and pane parts of target as a sesson and window if
they look like an ID.
2017-03-11 15:16:08 +00:00
Thomas Adam
392253f032 Merge branch 'obsd-master' 2017-03-10 00:01:16 +00:00
Nicholas Marriott
385a361bf8 Merge branch 'master' of github.com:tmux/tmux 2017-03-09 22:21:29 +00:00
Nicholas Marriott
a24cf4a5e1 Can only check for one with AC_CHECK_LIB. 2017-03-09 22:21:12 +00:00
nicm
55e73e3612 Clear the bracket paste mode when in the command prompt. 2017-03-09 22:00:46 +00:00
Thomas Adam
c5bdae466e Merge branch 'obsd-master' 2017-03-09 18:01:16 +00:00
nicm
bce1dee034 Move the client identify (display-panes) code into server-client.c. 2017-03-09 17:06:35 +00:00
nicm
dbfee6a468 Move server_fill_environ into environ.c and move some other common code
into it.
2017-03-09 17:02:38 +00:00
Nicholas Marriott
fd96ccfd80 No extra : for errx and warnx. 2017-03-09 16:49:37 +00:00
Nicholas Marriott
b79df1dc29 Compat code for strndup and strnlen. 2017-03-09 15:43:08 +00:00
Nicholas Marriott
180ebf0208 Merge branch 'master' of github.com:tmux/tmux 2017-03-09 15:39:36 +00:00
Nicholas Marriott
514a723f74 Solaris fixes, mostly from Dagobert Michelsen. 2017-03-09 15:39:13 +00:00
Thomas Adam
92434b0afd Merge branch 'obsd-master' 2017-03-08 22:01:19 +00:00
nicm
e8f2609ca4 Skip over padding cells when moving the cursor left or right. 2017-03-08 20:05:25 +00:00
Thomas Adam
41a01fc629 Merge branch 'obsd-master' 2017-03-08 16:01:15 +00:00
nicm
41b31fe240 Handle empty options correctly. 2017-03-08 14:43:40 +00:00
nicm
78ca1b0265 Always send smkx to the terminal outside, the keys we get from terminfo
are the keys when it is on.
2017-03-08 14:34:35 +00:00
Thomas Adam
3ea36830f3 Merge branch 'obsd-master' 2017-03-08 14:01:23 +00:00
nicm
6b2009ad72 Add a helper function for the most common format_create/defaults/expand
pattern.
2017-03-08 13:36:12 +00:00
Thomas Adam
5d3296c53b Merge branch 'obsd-master' 2017-03-07 15:32:28 +00:00
nicm
1e6e606f54 Need to flush before writing out cells we are not collecting, also add
some extra logging.
2017-03-07 13:48:28 +00:00
nicm
daac28febb If moving cells outside the current used count, update it. 2017-03-07 13:47:56 +00:00
Thomas Adam
69257bc0aa Merge branch 'obsd-master' 2017-03-06 10:01:21 +00:00
Nicholas Marriott
8684e60f51 Merge branch 'master' of github.com:tmux/tmux 2017-03-06 09:26:16 +00:00
Nicholas Marriott
fa27cbd035 Expand on OS X faffing, based on a diff from Kurtis Rader. 2017-03-06 09:24:41 +00:00
nicm
dc8fefe902 Collect strings correctly when on terminals that don't support UTF-8. 2017-03-06 09:02:59 +00:00
nicm
fba9ebcc0c When redrawing a combined UTF-8 characters in its existing position,
need to save and restore the cursor so that the next character goes into
the right place.
2017-03-06 09:02:36 +00:00
Thomas Adam
48a3dba6b9 Merge branch 'obsd-master' 2017-02-27 14:01:20 +00:00
Nicholas Marriott
2fa16eee53 Change to vim(1) script by Eric Pruitt. 2017-02-27 13:21:04 +00:00
nicm
e741a0bcd7 If splitw -b is used, insert the new pane before the current one in the
pane list. This means the numbering is in order (for example for
display-panes) and fixes a problem with redrawing the active pane
borders.
2017-02-27 13:07:57 +00:00
Thomas Adam
14dc2acc25 Merge branch 'obsd-master' 2017-02-22 10:01:12 +00:00
nicm
0414b1fc78 Minor bits: fix an array size, add comment, make grid_cell_entry static. 2017-02-22 09:01:32 +00:00
Thomas Adam
4b112c19f1 Merge branch 'obsd-master' 2017-02-21 18:01:12 +00:00
nicm
8a0b279c31 Change pane redraw to collect cells up as well, and simplify it a bit. 2017-02-21 16:25:04 +00:00
Thomas Adam
6b45464120 Merge branch 'obsd-master' 2017-02-21 16:01:15 +00:00
nicm
27ee34e7fa Don't need is1,is2,is3 so remove them. 2017-02-21 14:18:12 +00:00
Thomas Adam
e9819eef3c Merge branch 'obsd-master' 2017-02-21 12:01:16 +00:00
nicm
9e4c5133c8 Scrolling at least needs to be flushed before sending EL to the terminal
(but it is simpler to flush everything, so do that instead).
2017-02-21 10:30:15 +00:00
Thomas Adam
11e7915195 Reflect OBSD Makefile changes in Makefile.am 2017-02-21 09:24:53 +00:00
Thomas Adam
0ad2beae7e Merge branch 'obsd-master'
Conflicts:
	Makefile
2017-02-21 09:23:50 +00:00
Nicholas Marriott
55e76edd3c Improve NetBSD KERN_PROC2 bit, mostly from Kamil Rytarowski. 2017-02-19 08:31:05 +00:00
nicm
f27e1d07fc Add SGR 28 to clear hidden flag. 2017-02-19 07:55:11 +00:00
Nicholas Marriott
203d604bf7 Add to TODO. 2017-02-17 10:52:40 +00:00
Nicholas Marriott
ee7acde149 Update TODO. 2017-02-16 15:06:20 +00:00
nicm
82db1fa9e5 There are buggy terminals out there that do not move the cursor to 0,0
after CSR, so invalidate the cursor position rather than assuming 0,0.
2017-02-16 12:56:01 +00:00
nicm
c948c6b697 Handle insert cells when cursor at edge of screen correctly, and do a
full flush before insert.
2017-02-16 12:43:08 +00:00
nicm
c889e11375 Merge clear-history into capture-pane. 2017-02-16 12:18:38 +00:00
Thomas Adam
f734d81074 Merge branch 'obsd-master' 2017-02-16 12:01:21 +00:00
nicm
8b8d0963da Style nits. 2017-02-16 10:53:25 +00:00
Thomas Adam
c9f2dc5ee5 Merge branch 'obsd-master' 2017-02-15 12:01:15 +00:00
nicm
dd25a6cdc2 Do not clear to end of screen unless the pane is at the bottom. 2017-02-15 11:22:13 +00:00
Nicholas Marriott
47bc867ab9 Merge branch 'master' of github.com:tmux/tmux 2017-02-15 10:34:38 +00:00
Nicholas Marriott
b9b7daf3b2 Copy 24-bit-color.sh from iTerm2. 2017-02-15 10:34:20 +00:00
Thomas Adam
631a89954f Merge branch 'obsd-master' 2017-02-15 10:01:17 +00:00
Nicholas Marriott
36734afdd8 Hide or fix some warnings. 2017-02-15 08:54:21 +00:00
nicm
640d9e54b7 "status bar" -> "status line" for consistency, from Benjamin Dopplinger. 2017-02-15 08:47:55 +00:00
Nicholas Marriott
2b4c144f96 Remove vis.h. 2017-02-15 08:37:11 +00:00
Thomas Adam
ba3c1534e0 Merge branch 'obsd-master' 2017-02-14 20:01:12 +00:00
nicm
e340df2034 Make source-file look for files relative to the client working directory
(like load-buffer and save-buffer), from Chris Pickel. Also break the
where-is-this-file code out into its own function for loadb and saveb.
2017-02-14 18:13:05 +00:00
Thomas Adam
02e04477de Merge branch 'obsd-master'
Conflicts:
	server.c
2017-02-14 13:55:16 +00:00
nicm
4c2a78029d Collected cells may still need to be extended for RGB colours. 2017-02-13 16:05:30 +00:00
nicm
921880e00b Add not delete the event if more to write. 2017-02-10 15:39:43 +00:00
nicm
d22c15107b Don't use a bufferevent for the tty, so we can keep better track of what
is being written and when.

Also a manpage typo fix from jmc@.
2017-02-10 12:59:18 +00:00
nicm
c6a3446398 Instead of numbering session groups, give them a name which may be given
to -t instead of a target session. Also allow them to contain only one
session.
2017-02-09 15:04:53 +00:00
nicm
8de4c15dfa Document refresh-client -C. 2017-02-09 14:49:00 +00:00
Nicholas Marriott
c75cced07d Add to TODO. 2017-02-09 14:40:30 +00:00
Thomas Adam
96ad1d7779 Merge branch 'obsd-master' 2017-02-09 14:01:18 +00:00
nicm
b1fa3e25e4 Break the message storage function into its own function, useful for
debugging.
2017-02-09 12:09:33 +00:00
Thomas Adam
cb50a51127 Merge branch 'obsd-master' 2017-02-09 12:01:12 +00:00
nicm
b7ddfb39f3 Don't lie about the default size in the man page. 2017-02-09 12:00:42 +00:00
nicm
ddb3750c8b Combining characters need a full flush. 2017-02-09 10:09:14 +00:00
Thomas Adam
79409dc1cc Merge branch 'obsd-master' 2017-02-09 10:01:18 +00:00
nicm
fd6e46596d When an ordinary (not collected) cell is received, we need to flush any
delayed scrolling before drawing it.
2017-02-09 09:33:15 +00:00
Thomas Adam
743f772bef Merge branch 'obsd-master' 2017-02-09 02:01:17 +00:00
Thomas Adam
be033b1ed0 Merge branch 'obsd-master' 2017-02-09 00:01:12 +00:00
nicm
1811dc5271 Another helper function to write to terminal and log. 2017-02-08 23:53:03 +00:00
nicm
2f854969ff Do not adjust region lower by pane offset when scrolling up, it is
already an absolute position.
2017-02-08 22:42:07 +00:00
Thomas Adam
130b77edc7 Merge branch 'obsd-master' 2017-02-08 18:01:17 +00:00
nicm
05802a6fe3 window_copy_pagedown shouldn't reset the mode anymore, instead let the
caller do it so it can free the marks. Problem reported by attila at
stalphonsos dot com.
2017-02-08 17:33:51 +00:00
nicm
e100d465da Add support for scroll up escape sequence (CSI S) and use it when
possible instead of sending individual line feeds.
2017-02-08 17:31:09 +00:00
nicm
13a0b6bb3f Collect sequences of printable ASCII characters and process them
together instead of handling them one by one. This is significantly
faster. Sequences are terminated when we reach the end of the line, fill
the internal buffer, or a different character is seen by the input
parser (an escape sequence, or UTF-8).

Rather than writing collected sequences out immediately, hold them until
it is necessary (another screen modification, or we consume all
available data). This means we can discard changes that would have no
effect (for example, lines that would just be scrolled off the screen or
cleared). This reduces the total amount of data we write out to the
terminal - not important for fast terminals, but a big help with slow
(like xterm).
2017-02-08 16:45:18 +00:00
nicm
d4b006b9fa Fix clear start of line. 2017-02-08 16:18:20 +00:00
Thomas Adam
e09625e38b Merge branch 'obsd-master' 2017-02-08 16:01:17 +00:00
nicm
7475165cd8 Some other tidying bits. 2017-02-08 15:49:29 +00:00
nicm
ac1f294bb9 Add a helper to store a cell, and some tidying. 2017-02-08 15:41:41 +00:00
nicm
96b66f8fc3 Remove unnecessary duplicate check. 2017-02-08 15:24:48 +00:00
nicm
713f3b05f3 Improve some of the logging on resize. 2017-02-08 13:53:32 +00:00
Nicholas Marriott
9af5f3ff81 Give an example, from Timothee Cour. 2017-02-08 11:52:42 +00:00
Thomas Adam
a9a0039be4 Merge branch 'obsd-master' 2017-02-08 10:01:22 +00:00
nicm
cb80901d33 Log size of output buffer as well. 2017-02-08 08:54:45 +00:00
nicm
9cc02d1498 Trying to avoid the occasional newline by saving the last cell on screen
is not actually helping us much and just adds complexity, so don't
bother.
2017-02-08 08:50:10 +00:00
nicm
acb4bd9e56 Tweak how much we expand lines by. 2017-02-08 08:26:35 +00:00
nicm
35a0606de1 Remove event watermarks, don't work well enough to be worth it. 2017-02-08 08:25:12 +00:00
Thomas Adam
5aaf640629 Merge branch 'obsd-master' 2017-02-07 20:01:14 +00:00
nicm
c0a34821c1 Do not clear the scroll region, instead set it to the scroll region we
actually want.
2017-02-07 18:27:46 +00:00
nicm
20f5e377fb Remove a debugging leftover. 2017-02-07 18:06:42 +00:00
Thomas Adam
178289fb4c Merge branch 'obsd-master' 2017-02-07 18:01:13 +00:00
nicm
6ea36afc4b DECSLRM in xterm(1) appears to have a quirk where it can generate an
extra scroll of the entire terminal; issuing DECSTBM first prevents
this. Do that for now.
2017-02-07 17:13:28 +00:00
Thomas Adam
97fd291079 Merge branch 'obsd-master' 2017-02-07 16:01:13 +00:00
nicm
9491a5c1cf Unfortunately DECFRA does not handle default colours properly (it does
not reset colours when in SGR 0), so we can't use it without more
trouble than it is worth. Abandon the idea for now.
2017-02-07 14:33:37 +00:00
Nicholas Marriott
8872a0da8e Merge branch 'master' of github.com:tmux/tmux 2017-02-07 13:41:17 +00:00
Nicholas Marriott
0f5a2c86da Look for libtinfo before libncurses. 2017-02-07 13:40:36 +00:00
Thomas Adam
9f66fb4fd7 Merge branch 'obsd-master' 2017-02-07 00:01:13 +00:00
nicm
d60e585d9e Use DECFRA on VT420 compatible terminals (so, xterm) and ED on all
others for clearing panes.
2017-02-06 22:05:11 +00:00
Thomas Adam
dfdc23d86c Merge branch 'obsd-master' 2017-02-06 22:01:16 +00:00
Thomas Adam
7417e391d5 Merge branch 'obsd-master' 2017-02-06 20:01:15 +00:00
nicm
68e04907de Do not go through the whole attributes setting process if the new cell
is the same as the previous one.
2017-02-06 19:45:23 +00:00
nicm
10e14ae504 Add BCE for clear to start of screen, which was somehow missed. 2017-02-06 19:26:49 +00:00
Thomas Adam
1199f8fc59 Merge branch 'obsd-master' 2017-02-06 16:01:20 +00:00
nicm
e67548dc36 Cancel key table when switching session, unless the key is going to
repeat. Reported by Amos Bird.
2017-02-06 15:00:41 +00:00
Thomas Adam
446177a832 Merge branch 'obsd-master' 2017-02-06 14:01:16 +00:00
Nicholas Marriott
4eabd7ec90 Do not declare program_invocation_short_name because people can't make up their
mind what type it should be.
2017-02-06 13:34:19 +00:00
nicm
d150d9b384 Fix logging of CSI parameters. 2017-02-06 13:25:15 +00:00
nicm
3fd34e70e5 Only redraw the modified character when adding combining characters, not
the whole line.
2017-02-06 13:23:00 +00:00
Nicholas Marriott
50f25a8f05 Merge branch 'master' of github.com:tmux/tmux 2017-02-06 10:06:14 +00:00
Nicholas Marriott
c7c1018e9b Update sys/queue.h from OpenBSD. 2017-02-06 10:05:56 +00:00
Thomas Adam
7bccc82284 Merge branch 'obsd-master' 2017-02-05 02:01:12 +00:00
nicm
d091253a5d Missing va_end, from Anton Lindqvist. 2017-02-04 23:42:53 +00:00
Thomas Adam
e1c283325e Merge branch 'obsd-master' 2017-02-03 22:01:18 +00:00
nicm
5e6a8177e5 Cache status line position to reduce option lookups during output. 2017-02-03 21:01:02 +00:00
nicm
75adf8368a Expand lines more aggressively to reduce rate of allocations. 2017-02-03 20:53:03 +00:00
Thomas Adam
6c333cc486 Merge branch 'obsd-master' 2017-02-03 14:01:13 +00:00
nicm
7d23d019c0 Add a window or pane id "tag" to each format tree and use it to separate
jobs, this means that if the same job is used for different windows or
panes (for example in pane-border-format), it will be run separately for
each pane.
2017-02-03 11:57:27 +00:00
Thomas Adam
9b1f620aa0 Merge branch 'obsd-master' 2017-02-01 12:01:18 +00:00
nicm
dd0c814779 Implement "all event" (1003) mouse mode but in a way that works. The
main issue is that if we have two panes, A with 1002 and B with 1003, we
need to set 1003 outside tmux in order to get all the mouse events, but
then we need to suppress the ones that pane A doesn't want. This is easy
in SGR mouse mode, because buttons == 3 is only used for movement events
(for other events the trailing m/M marks a release instead), but in
normal mouse mode we can't tell so easily. So for that, look at the
previous event instead - if it is drag+release as well, then the current
event is a movement event.
2017-02-01 09:55:07 +00:00
Nicholas Marriott
9b9a5a292d Merge branch 'master' of github.com:tmux/tmux 2017-01-31 12:52:50 +00:00
Nicholas Marriott
c54a5d9fb3 Add wchar.h to compat.h, from Koichi Shiraishi. 2017-01-31 12:51:53 +00:00
Thomas Adam
d8da761d54 Merge branch 'obsd-master' 2017-01-31 00:01:12 +00:00
nicm
3408595f77 When a flag option is used in a format, it should use the number form
not string.
2017-01-30 21:41:17 +00:00
Thomas Adam
9094f01c6b Merge branch 'obsd-master' 2017-01-30 00:01:13 +00:00
nicm
b6099f31ea Add -n to break-pane. 2017-01-29 22:10:55 +00:00
Thomas Adam
4b482c95c3 Merge branch 'obsd-master' 2017-01-28 18:01:12 +00:00
nicm
54309cc25d Do not clear the key table when changing session on a client, so that
switch-client and friends work with bind -n.
2017-01-28 16:11:27 +00:00
Nicholas Marriott
503af3df54 This link is better. 2017-01-26 19:57:16 +00:00
Nicholas Marriott
b2e909b252 Merge branch 'master' of github.com:tmux/tmux 2017-01-26 19:55:45 +00:00
Nicholas Marriott
a4367b44fb Add ISSUE_TEMPLATE. 2017-01-26 19:55:16 +00:00
Thomas Adam
78c0b96004 Merge branch 'obsd-master' 2017-01-26 02:01:12 +00:00
nicm
776ce8a9d5 Clear option before adding to array if no -a, reported by Michael
Nickerson.
2017-01-25 23:50:51 +00:00
Nicholas Marriott
ea70e68a51 -paths.h. 2017-01-25 16:39:02 +00:00
Nicholas Marriott
0f9354eec2 Bad merge. 2017-01-25 16:38:13 +00:00
Thomas Adam
21d8f77a0d Merge branch 'obsd-master' 2017-01-25 16:01:13 +00:00
nicm
163732e89f Revert previous for now, it will break TERM=screen. 2017-01-25 14:36:08 +00:00
nicm
0a63ab4f0f If xterm-keys is on, use xterm(1) style keys for Home and End as well as
modified keys.
2017-01-25 14:24:54 +00:00
Nicholas Marriott
3e495b4001 compat/* should not include tmux.h. 2017-01-25 13:49:01 +00:00
Thomas Adam
418ab1a553 Merge branch 'obsd-master' 2017-01-24 22:01:13 +00:00
nicm
ffc28a7765 Fix set -u on array options. 2017-01-24 20:24:54 +00:00
nicm
4b2821ff98 Make update-environment an array as well. 2017-01-24 20:15:32 +00:00
nicm
b77dd75b57 Convert terminal-overrides to an array option. 2017-01-24 20:05:15 +00:00
nicm
16e43d6a42 Remove some lies about terminal-overrides from tmux.1. 2017-01-24 20:01:34 +00:00
Thomas Adam
f38a6bbd81 Merge branch 'obsd-master' 2017-01-24 20:01:12 +00:00
nicm
126d364abe server-info can become an alias rather than a command. 2017-01-24 19:59:19 +00:00
nicm
85338bb75f Add support for custom command aliases, this is an array option which
contains items of the form "alias=command". This is consulted when an
unknown command is parsed.
2017-01-24 19:53:37 +00:00
nicm
61fce272ea If given an array option without an index either show or set all items,
and support -a for array options. Allow the separator for set to be
specified in the options table (will be used for backwards compatibility
later).
2017-01-24 19:11:46 +00:00
Thomas Adam
f1282a683d Merge branch 'obsd-master' 2017-01-24 14:01:15 +00:00
Nicholas Marriott
c68ea386d1 pty.c needs compat.h. 2017-01-24 13:34:08 +00:00
nicm
3d74e89a39 Shorten a long line, and don't leak buffer in paste_add if size is zero. 2017-01-24 13:28:33 +00:00
Nicholas Marriott
a3d5bfcece Define away pledge() on !OpenBSD. 2017-01-23 12:27:58 +00:00
Nicholas Marriott
1ebe79dd62 Use forkpty() except on OpenBSD. 2017-01-23 12:26:06 +00:00
Thomas Adam
b3a724f30c Merge branch 'obsd-master'
Conflicts:
	Makefile
	tmux.c
2017-01-23 12:20:43 +00:00
nicm
98e7fbb2ac Open /dev/ptm before pledge() and save it to be used for PTMGET later
(this means inlining forkpty()).

ok deraadt
2017-01-23 10:09:43 +00:00
Thomas Adam
d2eab39ffa Merge branch 'obsd-master' 2017-01-22 20:01:12 +00:00
Nicholas Marriott
aa70f28069 Merge branch 'master' of github.com:tmux/tmux 2017-01-22 19:14:10 +00:00
Nicholas Marriott
acf331f7f1 Add b64_pton as well. 2017-01-22 19:12:15 +00:00
nicm
4ede35c48c Accept the OSC 52 escape sequence inside tmux to add a new buffer, from
harry dot gindi at live dot com.
2017-01-22 19:00:01 +00:00
Thomas Adam
c17b0a202a Merge branch 'obsd-master' 2017-01-20 16:01:11 +00:00
nicm
46572ba904 Print error rather than fatal() if tcgetattr() fails, which is much more
useful to user.
2017-01-20 14:02:33 +00:00
Nicholas Marriott
61af9d7cc2 Look for ncursesw as well as ncurses, based on a change from Bert van Hall. 2017-01-19 15:31:22 +00:00
Nicholas Marriott
b98b4e23a3 Put version in log in portable tmux. 2017-01-18 17:35:41 +00:00
Nicholas Marriott
7e4908f751 If --enable-{utf8proc,utempter} is given, do not build without it. 2017-01-18 14:32:50 +00:00
Nicholas Marriott
787f9de5d8 vis.h comes from compat.h. 2017-01-18 12:16:14 +00:00
Thomas Adam
044999ce6d Merge branch 'obsd-master' 2017-01-18 12:01:11 +00:00
nicm
faa0570309 Plain stravis() because it will mangle UTF-8 characters, so add
utf8_stravis() which calls our existing utf8_strvis() and use it instead
2017-01-18 10:08:05 +00:00
Thomas Adam
6d37984f4f Merge branch 'obsd-master' 2017-01-18 10:01:12 +00:00
nicm
4bb5a1d6a7 Run arguments through vis() as well when printing them. 2017-01-18 10:00:50 +00:00
nicm
649c0d8e91 Do not reset idx, it has just been set. 2017-01-18 08:43:21 +00:00
nicm
373541104b options_match needs to explicitly check for user options. 2017-01-18 08:40:50 +00:00
Thomas Adam
64c486ae81 Merge branch 'obsd-master' 2017-01-17 02:01:11 +00:00
nicm
6b6b0e91d0 Correctly handle -style options without all of a corresponding -fg/-bg/-attr. 2017-01-16 23:45:08 +00:00
Nicholas Marriott
c0346701df Fix VIS_DQ check. 2017-01-16 18:20:50 +00:00
Thomas Adam
7e110b9d99 Merge branch 'obsd-master' 2017-01-16 15:36:02 +00:00
Nicholas Marriott
f20e3ee62c We need VIS_DQ in vis.h as well. 2017-01-16 15:01:14 +00:00
nicm
ef15b4195f Revert WIP parts of previous I didn't mean to commit yet. 2017-01-16 14:52:25 +00:00
nicm
68db958477 getopt() has a struct option so just return to using options_entry. 2017-01-16 14:49:14 +00:00
Nicholas Marriott
997b11741c Remove vis.h which comes from compat. 2017-01-16 12:09:04 +00:00
Thomas Adam
7b60645732 Merge branch 'obsd-master' 2017-01-16 00:01:10 +00:00
Thomas Adam
c9fcb76651 Merge branch 'obsd-master' 2017-01-15 22:01:11 +00:00
nicm
52847a9518 It is silly for cmd_list_parse to return an integer error when it could
just return NULL.
2017-01-15 22:00:56 +00:00
nicm
3054846143 -q flag now needs to be checked in a couple more places. 2017-01-15 20:50:34 +00:00
nicm
2b0bc9f1c5 Major tidy up and rework of options tree and set-option/show-options
commands this pushes more of the code into options.c and ties it more
closely to the options table rather than having an unnecessary
split. Also add support for array options (will be used later). Only
(intentional) user visible change is that show-options output is now
passed through vis(3) with VIS_DQ so quotes are escaped.
2017-01-15 20:48:41 +00:00
nicm
404214b0ac Remove unused quiet option. 2017-01-15 20:16:22 +00:00
nicm
a3cf995017 Append needs to go old,new not new,old... 2017-01-15 20:14:36 +00:00
Thomas Adam
4f077fe62c Merge branch 'obsd-master' 2017-01-14 20:01:13 +00:00
nicm
e06efab9da killp -a should not kill the window if only one pane. 2017-01-14 18:53:08 +00:00
Thomas Adam
780dd7ac82 Merge branch 'obsd-master' 2017-01-13 14:01:13 +00:00
Thomas Adam
2311bbd28a Merge branch 'obsd-master' 2017-01-13 12:01:12 +00:00
nicm
08d21936e4 options_get_style return const too. 2017-01-13 11:58:49 +00:00
nicm
22a528905d Make options_get_string return const string. 2017-01-13 11:56:43 +00:00
nicm
95950bf668 Add -E to detach-client to exec a command to replace the client instead
of exiting it, useful if tmux wasn't exec'd itself. From Jenna Magius.
2017-01-13 10:12:12 +00:00
Thomas Adam
d4cb178249 Merge branch 'obsd-master' 2017-01-12 16:01:13 +00:00
nicm
24cba5907b Simplify appending to string options. 2017-01-12 15:36:35 +00:00
Thomas Adam
1eb9500644 Merge branch 'obsd-master' 2017-01-12 12:01:10 +00:00
nicm
dad3090d32 Put all palette functions together in the file. 2017-01-12 10:15:55 +00:00
Thomas Adam
4a76861925 Merge branch 'obsd-master' 2017-01-12 02:01:11 +00:00
nicm
9b6aeacdc0 aixterm colours can be used if -2 is given, as well as if TERM tells us
the terminal has >=16 colours.
2017-01-12 00:30:41 +00:00
nicm
0752fdaf6a Erm the aixterm colours should start at 8, not 7. 2017-01-12 00:24:28 +00:00
nicm
9e786030df Fix setting the palette of aixterm colours (90-97). 2017-01-12 00:19:32 +00:00
Thomas Adam
33ebb9ec39 Merge branch 'obsd-master' 2017-01-12 00:01:13 +00:00
nicm
74c40d04ea Be less aggressive about turning margins off. 2017-01-11 23:10:04 +00:00
nicm
3bb14001b9 Add some missing special keys to key_string_lookup_key, fix a mouse
check in server_client_handle_key, and tweak a comment.
2017-01-11 22:36:07 +00:00
Thomas Adam
d87ab0cadf Merge branch 'obsd-master' 2017-01-11 18:01:13 +00:00
nicm
bf6a5c056d Add a format for terminal type. 2017-01-11 16:09:57 +00:00
nicm
7497ecd979 Use a macro for looking up tty types. 2017-01-11 16:05:46 +00:00
Thomas Adam
0d19d78fff Merge branch 'obsd-master' 2017-01-11 16:01:16 +00:00
nicm
458b6eb600 Some tidying and tweaks to options code. 2017-01-11 14:56:44 +00:00
Thomas Adam
8f79b079cd Merge branch 'obsd-master' 2017-01-10 22:01:14 +00:00
Thomas Adam
db8dff6814 Merge branch 'obsd-master' 2017-01-10 20:01:12 +00:00
nicm
5526627558 Minor tidying in a couple of commands. 2017-01-10 19:45:55 +00:00
Nicholas Marriott
ba35e8f292 15 minutes is not 1800 seconds, but just remove lock-after-time because it won't work for Linux folks without additional configuration 2017-01-10 19:33:22 +00:00
Nicholas Marriott
2283f19876 -temacs-copy should now be -Tcopy-mode 2017-01-10 19:31:34 +00:00
Nicholas Marriott
152bfa02f0 Merge branch 'master' of github.com:tmux/tmux 2017-01-10 19:27:23 +00:00
Nicholas Marriott
a5c89a1802 Change around the example .tmux.conf to show some newer features. 2017-01-10 19:26:54 +00:00
nicm
aa4de2d4b2 Need to escape ; twice because the command list parser will eat one,
reported by Theo Buehler.
2017-01-10 18:10:24 +00:00
Thomas Adam
570943beb7 Merge branch 'obsd-master' 2017-01-10 14:01:12 +00:00
Thomas Adam
1e12e1d843 Merge branch 'obsd-master' 2017-01-10 12:01:10 +00:00
nicm
5ea7a00eba Quote backslash as well for %%%. 2017-01-10 11:58:30 +00:00
nicm
e78142232f Some manpage fixes: rephrase a convoluted sentence, make the names of
some keys more standard, and use Ql instead of Dq.
2017-01-10 10:08:59 +00:00
Thomas Adam
628f3ad9f4 Merge branch 'obsd-master' 2017-01-10 10:01:11 +00:00
jmc
40fddfbdd6 avoid unneccessary markup; tweaked and ok nicm 2017-01-10 07:55:48 +00:00
Thomas Adam
2c862b04af Merge branch 'obsd-master' 2017-01-09 22:01:12 +00:00
Nicholas Marriott
36619607ba Add a format for the version. 2017-01-09 21:44:19 +00:00
nicm
d2d984647e Add %if/%endif for conditionals when parsing configuration files, the
argument is a format (the new == and != are useful).
2017-01-09 21:28:56 +00:00
nicm
844f2eacf4 Add simple comparisons in formats: #{==:a,b} and #{!=:a,b} ("a" and "b"
are expanded so can compare formats). And expand the condition to
#{?a,b,c} (the "a" part) if it doesn't work as a simple lookup.

Also add FORMAT_NOJOBS flag to disable jobs in a format.
2017-01-09 21:03:25 +00:00
Thomas Adam
95f5d406e5 Merge branch 'obsd-master' 2017-01-09 20:01:12 +00:00
nicm
561b5c6fdb source-file -q needs to apply to glob(3) too. 2017-01-09 19:29:12 +00:00
nicm
5330a2a85d Run the source-file pattern through glob(3). 2017-01-09 19:27:00 +00:00
Nicholas Marriott
d90fa2ec13 Tweak TODO file. 2017-01-09 17:48:30 +00:00
Thomas Adam
325c85a5c1 Merge branch 'obsd-master' 2017-01-07 18:01:11 +00:00
Thomas Adam
29e64a8c64 Merge branch 'obsd-master' 2017-01-07 16:01:17 +00:00
nicm
c05002b0f2 Add note about ccc and initc so people who want it can see it is
possible.
2017-01-07 15:40:23 +00:00
nicm
314e933914 Add support for the OSC 4 and OSC 104 palette setting escape sequences,
from S Gilles.
2017-01-07 15:28:13 +00:00
Thomas Adam
a3428487a7 Merge branch 'obsd-master' 2017-01-06 14:01:15 +00:00
nicm
cae0fbbe8c Nits found with clang. 2017-01-06 13:26:09 +00:00
nicm
461217d0f0 Incremental search in copy mode (on for emacs keys by default) - much
the same as normal searching but updates the cursor position and marked
search terms as you type. C-r and C-s in the prompt repeat the search,
once finished searching (with Enter), N and n work as before.
2017-01-06 11:57:03 +00:00
Thomas Adam
58642011df Merge branch 'obsd-master' 2017-01-05 10:01:11 +00:00
nicm
9a56671a75 Highlight all occurrences of search string after searching in copy mode. 2017-01-05 09:07:15 +00:00
Thomas Adam
45dbbb78b0 Merge branch 'obsd-master' 2017-01-03 00:01:12 +00:00
nicm
43e8f60bc6 Escape backspace for capture-pane -P, from George Nachman. 2017-01-02 22:42:19 +00:00
Thomas Adam
f5c5847788 Merge branch 'obsd-master' 2016-12-30 16:01:15 +00:00
nicm
1015b124d5 Change the xterm-keys option to default to on, so that tmux will
generate xterm(1) escape sequences for function keys with modifiers.

With the option off most of these keys are ignored by default, except
for ctrl + arrows which use a variant that nothing else seems to use and
I don't remember why we chose. The xterm escape sequences are now the
most common.

Prompted by a question from mpi@.
2016-12-30 13:49:34 +00:00
Thomas Adam
d3328a3b1e Merge branch 'obsd-master' 2016-12-28 12:01:14 +00:00
nicm
70ba3c147f Fix the prefer unattached session behaviour of
attach-session/switch-client, reported by Thomas Sattle.
2016-12-28 10:34:34 +00:00
Nicholas Marriott
af56e50f74 utempter is no longer the default, and mention ncurses. 2016-12-20 16:28:11 +00:00
Thomas Adam
00445ebadd Merge branch 'obsd-master' 2016-12-14 20:01:11 +00:00
nicm
e36f932f62 Fix up winlink lists after swap-window. 2016-12-14 17:38:59 +00:00
Thomas Adam
dda701d95f Merge branch 'obsd-master' 2016-12-12 02:01:27 +00:00
nicm
b851c628f4 -N without arguments needs to set prefix count for the mode command, so
that M-1 etc work. Reported by Theo Buehler.
2016-12-11 22:55:25 +00:00
Thomas Adam
a64b7cfe5d Merge branch 'obsd-master' 2016-12-10 00:01:11 +00:00
nicm
bee95bf378 Spacing nits. 2016-12-09 21:39:27 +00:00
Thomas Adam
75135ded09 Merge branch 'obsd-master' 2016-12-09 00:01:12 +00:00
nicm
2a7b4bb017 Fix send-keys with UTF-8. 2016-12-08 22:15:37 +00:00
Thomas Adam
d3ede11212 Merge branch 'obsd-master' 2016-12-08 00:01:10 +00:00
nicm
5819d2a9d7 Do not clear the prompt when a message is shown, just leave it around and
return to it when the message is finished.
2016-12-07 23:03:04 +00:00
Thomas Adam
b9fa8f12d7 Merge branch 'obsd-master' 2016-12-07 10:01:12 +00:00
nicm
5ea143f521 Only skip moving the cursor if it is already in the last position _on
the same line_, fixes redraw bug reported by patrick keshishian.
2016-12-07 09:16:55 +00:00
nicm
a8f3ad4487 Make prefix work in all tables (except the prefix table). Users who want
to avoid this can set prefix to "none" and bind send-prefix
themselves. Allows C-b t be bound in the copy mode tables again, pointed
out by millert@.
2016-12-07 09:16:13 +00:00
Thomas Adam
6749a30a6e Merge branch 'obsd-master' 2016-11-30 14:01:11 +00:00
nicm
1a6156d8fd Fix check for cursor at end of line. 2016-11-30 13:20:02 +00:00
Thomas Adam
1fccfd7be5 Merge branch 'obsd-master' 2016-11-29 14:01:11 +00:00
nicm
6b46c62bb4 Make send -N work for all keys, not just in copy mode. From Artem Fokin. 2016-11-29 12:54:46 +00:00
Thomas Adam
d7837cca52 Merge branch 'obsd-master' 2016-11-28 20:01:10 +00:00
nicm
9fc925ac51 When comparing ocy to orlower in tty_cmd_cell, there is no need to add
yoff (because they are both already relative to the pane). Also fix some
other minor nits.
2016-11-28 17:50:00 +00:00
Thomas Adam
2864a31311 Merge branch 'obsd-master' 2016-11-24 20:01:10 +00:00
nicm
6f8cedb1bc The mouse valid flag needs to be correct before we fire the dragging
callback, so move the callback outside of server_client_check_mouse and
use a new special key code to indicate it.
2016-11-24 18:45:45 +00:00
Thomas Adam
a02d95a313 Merge branch 'obsd-master' 2016-11-24 16:01:11 +00:00
nicm
84319aa8f0 If in the middle of a drag, don't use an invalid key, just use
KEYC_MOUSE as a placeholder. Reported by Artem Fokin.
2016-11-24 14:38:55 +00:00
nicm
0d1be2e328 Fix so that we work out the right pane from mouse events - we were doing
so too early, before the mouse event was necessarily valid, so could end
up using the pane from the previous mouse event, or the active pane.

It is important that we use the right pane now that different panes can
have different key tables (for copy mode).

Fixes problem reported by Greg Hurrell.
2016-11-24 13:46:50 +00:00
nicm
7e6c2cb238 Make the selection able to exist independent of the cursor position, so
that it is not affected by scrolling. If MouseDragEnd1Pane is bound to
the new "stop-selection" command:

    bind -Tcopy-mode MouseDragEnd1Pane stop-selection

A selection made with the mouse will stay as it is after button 1 is
released. (It also works bound to a key.)

From Artem Fokin.
2016-11-24 13:38:44 +00:00
Thomas Adam
8a8001350d Merge branch 'obsd-master' 2016-11-23 18:01:19 +00:00
nicm
6de466cf8b For mouse keys, use the mouse pane as the default current pane. 2016-11-23 17:01:24 +00:00
nicm
24916f2f6e Error on invalid modifier keys. 2016-11-23 16:44:42 +00:00
Thomas Adam
442e49f51c Merge branch 'obsd-master' 2016-11-17 12:01:10 +00:00
nicm
3cf19d6dd0 Key running commands for #() by the unexpanded command, and run them
again if the expanded form changes (otherwise at most once per second as
usual). Fixes issues reported by Gregory Pakosz.
2016-11-17 10:06:08 +00:00
Thomas Adam
759953cb8d Merge branch 'obsd-master' 2016-11-16 14:01:11 +00:00
nicm
ddf7ac5ae4 Fix calculation of whether we need a region for drawing a cell (only if
full width and at the edge of the region), otherwise clear the region entirely.
2016-11-16 13:31:22 +00:00
Thomas Adam
06fd3b00ff Merge branch 'obsd-master' 2016-11-16 12:01:11 +00:00
nicm
a8e2d851fe Don't error if renaming a session to its current name, from shik dot
chen at gmail dot com.
2016-11-16 11:41:17 +00:00
nicm
81f1d625af Do not stop dragging when the wheel is pressed, from Artem Fokin. 2016-11-16 11:37:16 +00:00
Thomas Adam
0f5b7814b5 Merge branch 'obsd-master' 2016-11-16 10:01:10 +00:00
nicm
5636d38a9d Initialize modeprefix to 1 properly in window_pane_create, from Artem Fokin. 2016-11-16 09:22:16 +00:00
Thomas Adam
12c49fa3bd Merge branch 'obsd-master' 2016-11-16 02:01:11 +00:00
nicm
e88b74350f The target validity check used window_pane_visible but that may be false
if the pane is zoomed, so instead add a new function to just check if
the pane is actually on screen (most commands still want to accept panes
invisible by zoom). Also reject panes outside the window for various
special targets. Problem reported by Sean Haugh.
2016-11-16 00:24:03 +00:00
Thomas Adam
1afe9e98de Merge branch 'obsd-master' 2016-11-15 16:01:10 +00:00
nicm
c34a79b152 Turn on margins, with a couple of fixes (only limit to the pane for line
feeds, and do not move cursor to end for full width panes).
2016-11-15 15:17:28 +00:00
nicm
d81a5c630f And of course I just find a bug, disable previous for now. 2016-11-15 14:08:27 +00:00
nicm
0ace779cde Initial attempt to make use of left and right margins if the terminal
supports them (that is, if it advertises itself as a VT420 - probably
just xterm). These are the vertical equivalent of the scroll region and
allow much faster scrolling of panes that do not take up the full width
of the terminal.
2016-11-15 14:02:32 +00:00
Thomas Adam
fe7d9af331 Merge branch 'obsd-master' 2016-11-15 12:01:18 +00:00
nicm
9fe43d6acb Add copy-pipe-and-cancel, from Artem Fokin. 2016-11-15 09:53:23 +00:00
Thomas Adam
9908681ba8 Merge branch 'obsd-master' 2016-11-14 18:01:13 +00:00
nicm
afbf0d42a7 rotate-window needs to unzoom, problem reported by Sean Haugh. 2016-11-14 16:27:12 +00:00
Thomas Adam
7177eeaa42 Merge branch 'obsd-master' 2016-11-12 20:01:10 +00:00
nicm
db2412e2ac Apply the right fix for run -b, used the wrong diff before. 2016-11-12 19:05:53 +00:00
nicm
b7398a4918 Do not execute commands for a client until it has identified, fixes
problem reported by Frank Terbeck.
2016-11-12 19:04:41 +00:00
Thomas Adam
afdef6d122 Merge branch 'obsd-master' 2016-11-11 12:01:11 +00:00
nicm
36f8fa316d Do not crash with run-shell -b and no window pane available, reported by
Sergei Dyshel.
2016-11-11 11:37:25 +00:00
Thomas Adam
13f1a922e1 Merge branch 'obsd-master' 2016-11-04 20:01:11 +00:00
nicm
f947d25c9d Do not try to set the CHANGED flag on windows with no active pane, fixes
problem reported by Nelo-T Wallus.
2016-11-04 18:56:25 +00:00
Thomas Adam
1de107c405 Merge branch 'obsd-master' 2016-11-04 16:01:11 +00:00
nicm
353439acee enum values need to fit in 32 bits; we only use enum for numbering and
Unicode characters fit in 24 bits, so we can leave key_code as 64 bits
and change KEYC_BASE down to 0x10000000.
2016-11-04 14:47:38 +00:00
Nicholas Marriott
a44024a795 Note about TERM. 2016-11-04 13:18:09 +00:00
Thomas Adam
15b6774f9b Merge branch 'obsd-master' 2016-11-02 14:01:10 +00:00
nicm
382e09bed1 Make an empty state on error rather than leaving something partially
created (which now is now a fatal() later).
2016-11-02 13:35:36 +00:00
Thomas Adam
5da94182ae Merge branch 'obsd-master' 2016-11-01 10:01:10 +00:00
nicm
c83feeb6f8 Clear window alert flags after setting winlink alert flags, fixes problem
reported by Tommy Allen.
2016-11-01 09:07:18 +00:00
Nicholas Marriott
178894b0fe Do not force symbols to width 1, from Yen Chi Hsuan. 2016-10-28 19:58:14 +01:00
Nicholas Marriott
4dbbcff72b Merge branch 'master' of github.com:tmux/tmux 2016-10-27 18:28:53 +01:00
Nicholas Marriott
4aa5dd0ee0 Add a CONTRIBUTING file with some information on opening issues. 2016-10-27 18:28:21 +01:00
Thomas Adam
b6f00a3945 Merge branch 'obsd-master' 2016-10-26 14:01:13 +01:00
nicm
abea17afd9 Buffer name can be NULL, check before strdup(). 2016-10-26 11:48:07 +00:00
Thomas Adam
f523fddf6a Merge branch 'obsd-master' 2016-10-25 10:01:09 +01:00
nicm
99946aaaaf Do not handle activity or silence alerts in the current window, reported
by jasper@.
2016-10-25 07:24:10 +00:00
Thomas Adam
5f9ba2f223 Merge branch 'obsd-master' 2016-10-21 16:01:11 +01:00
nicm
8084a2c9e6 Add %%% to substitute with quotes escaped (convert " to \"). Use this
for the prompts in copy mode. Fixes problems with jumping to ' reported
by Theo Buehler.
2016-10-21 13:51:59 +00:00
Nicholas Marriott
b951f0621c Put AM_* back, but this time do a dance in configure.ac so that we can keep
using CFLAGS for the tests.
2016-10-19 15:20:21 +01:00
Thomas Adam
28a31201d3 Merge branch 'obsd-master' 2016-10-19 12:01:11 +01:00
nicm
99c262b7d0 Do not have a default binding for C-b in copy-mode-vi or it conflicts
with the default prefix. Reported by natano@.
2016-10-19 09:24:57 +00:00
nicm
899e629bf0 Alerts are too slow, so rather than walking all sessions and windows,
add a link of winlinks to each window and a pointer to the session to
each winlink. Also rewrite the alerts processing to return to the old
behaviour (alert in any window sets the flag on any winlink).
2016-10-19 09:22:07 +00:00
Thomas Adam
4c6eb6cc2f Merge branch 'obsd-master' 2016-10-19 10:01:10 +01:00
nicm
bc27451e15 Move session-create hook out of session_create so it works with grouped sessions. 2016-10-19 08:17:11 +00:00
Nicholas Marriott
1fbb7f1a41 Merge branch 'master' of github.com:tmux/tmux 2016-10-18 23:23:49 +01:00
Nicholas Marriott
3742f66abb Revert the AM_* change, I can't find a way to make AC_CHECK_HEADER use
LIBEVENT_CFLAGS.
2016-10-18 23:19:08 +01:00
Thomas Adam
3a6beea064 Merge branch 'obsd-master' 2016-10-18 22:01:12 +01:00
nicm
e0e9a54a32 Clear cell entry with grid_default_entry not grid_default_cell. 2016-10-18 19:52:49 +00:00
Nicholas Marriott
ec47907772 I don't remember why we have make clean in dist-hook; remove it. 2016-10-18 20:41:31 +01:00
Nicholas Marriott
bd1dc89a5d *.h can go in dist_tmux_SOURCES, from Dilyan Palauzov. 2016-10-18 20:34:18 +01:00
nicm
fb109ae97d xterm-keys was in the wrong place in the list; Dilyan Palauzov. 2016-10-18 19:25:26 +00:00
Nicholas Marriott
66d637be3d Merge branch 'master' of github.com:tmux/tmux 2016-10-18 20:21:13 +01:00
Nicholas Marriott
ba9f47c544 Rename found_debug to enable_debug. 2016-10-18 20:19:24 +01:00
Thomas Adam
9b991a7301 Merge branch 'obsd-master' 2016-10-18 18:01:11 +01:00
Thomas Adam
0041e40ca8 Merge branch 'obsd-master' 2016-10-18 16:01:11 +01:00
nicm
a0998e42b7 Make grid_clear_cell set up the entry properly for 256 and RGB cells. 2016-10-18 14:56:17 +00:00
nicm
cf7289662f Tweak a couple of log statements. 2016-10-18 12:51:26 +00:00
Thomas Adam
8576ecaf32 Merge branch 'obsd-master' 2016-10-18 12:01:10 +01:00
Thomas Adam
b3ab39c4d9 Merge branch 'obsd-master' 2016-10-18 10:01:11 +01:00
nicm
2e5c49a1fd Give each item on queue a name for better logging. 2016-10-18 08:46:43 +00:00
nicm
8763bced76 Zero dirty count after flushing. 2016-10-18 08:39:18 +00:00
nicm
c2f88373e7 Store the right size in the pipe offset for pipe-pane. 2016-10-18 07:38:16 +00:00
Nicholas Marriott
7d5fd5fcd0 Preserve existing AM_CPPFLAGS and AM_LDFLAGS values. 2016-10-17 21:51:21 +01:00
Nicholas Marriott
f6c49cecc1 One extra empty line not in OpenBSD, and tweak a #define style. 2016-10-17 19:25:45 +01:00
Nicholas Marriott
7ba845297f CFLAGS/CPPFLAGS/LDFLAGS -> AM_*, requested by Dilyan Palauzov. 2016-10-17 19:14:56 +01:00
Nicholas Marriott
733185d0a9 Can use enable_* rather than adding our own found_* variables, from Dilyan Palauzov. 2016-10-17 19:09:38 +01:00
Thomas Adam
d54e990c4f Merge branch 'obsd-master' 2016-10-17 00:01:11 +01:00
nicm
fe106842c8 Use notifys for alerts too. 2016-10-16 22:18:04 +00:00
nicm
41e633acf5 Use the notify name string instead of going via an enum and change
existing hooks to use notifys instead.
2016-10-16 22:06:40 +00:00
Thomas Adam
1a6e696b08 Merge branch 'obsd-master' 2016-10-16 22:01:14 +01:00
Nicholas Marriott
d401340c51 Update TODO. 2016-10-16 20:59:43 +01:00
nicm
d15d54c2c8 Add hook_session and hook_window formats to get information on the
affected session or window when a hook fires. Enable session-created and
session-closed hooks now that that is available.
2016-10-16 19:55:52 +00:00
nicm
3f35b5299f Provide a way for hooks to tag formats onto the commands they fire so
that the user can get at additional information - now used for the
"hook" format, more to come.
2016-10-16 19:36:37 +00:00
nicm
026ad08b56 Notifys can go via the command queue instead of using their own queue. 2016-10-16 19:15:02 +00:00
nicm
b342bd0b46 Mass rename struct cmd_q to struct cmdq_item and related. 2016-10-16 19:04:05 +00:00
Thomas Adam
c67b702588 Merge branch 'obsd-master' 2016-10-16 20:01:10 +01:00
nicm
ddc4512d2e Rewrite command queue handling. Each client still has a command queue,
but there is also now a global command queue. Instead of command queues
being dispatched on demand from wherever the command happens to be
added, they are now all dispatched from the top level server
loop. Command queues may now also include callbacks as well as commands,
and items may be inserted after the current command as well as at the end.

This all makes command queues significantly more predictable and easier
to use, and avoids the complex multiple nested command queues used by
source-file, if-shell and friends.

A mass rename of struct cmdq to a better name (cmdq_item probably) is
coming.
2016-10-16 17:55:14 +00:00
Thomas Adam
3d8efdf310 Merge branch 'obsd-master' 2016-10-16 02:01:11 +01:00
nicm
bfe14b5312 Only use pane with run-shell if -t is given. 2016-10-15 23:06:39 +00:00
Thomas Adam
a15939b502 Merge branch 'obsd-master' 2016-10-15 14:01:10 +01:00
jmc
4fbf564292 zap double .Pp; 2016-10-15 12:34:02 +00:00
Thomas Adam
59d1147469 Merge branch 'obsd-master' 2016-10-15 12:01:14 +01:00
nicm
e7990375cb Give window_create and window_create1 better names. 2016-10-15 09:27:52 +00:00
Thomas Adam
623e54788e Merge branch 'obsd-master' 2016-10-15 02:01:12 +01:00
nicm
3f138dc40c Rename a function for consistency and some spacing nits. 2016-10-15 00:12:58 +00:00
nicm
63b2547a02 Fire hooks on the simple notifys (window-renamed and session-renamed),
the complicated ones get no hooks for now (more to come).
2016-10-15 00:09:30 +00:00
nicm
9b3ae84993 Drain notifys once at the end of the server loop instead of doing it
from the end of every command queue (which could be nested).
2016-10-15 00:01:01 +00:00
Thomas Adam
3d2686a236 Merge branch 'obsd-master' 2016-10-15 00:01:10 +01:00
nicm
ed971268be Add CMD_AFTERHOOK flag to the easy commands that don't need any special handling. 2016-10-14 22:14:22 +00:00
nicm
d413a945ac Don't make assumptions about line wrap on !xenl terminals, means that
using a wrong TERM without xenl is not so broken if used on a sensible
terminal.
2016-10-14 21:48:00 +00:00
Thomas Adam
9d58febc8f Merge branch 'obsd-master' 2016-10-14 22:01:11 +01:00
Thomas Adam
33fbf82ac0 Merge branch 'obsd-master' 2016-10-14 20:01:13 +01:00
nicm
1721d1994e source-file and some other commands can recurse back into cmdq_continue,
which could potentially free the currently running command, so we need
to take a reference to it in cmdq_continue_one.

Fixes problem reported by Theo Buehler.
2016-10-14 18:41:53 +00:00
nicm
0ec18e537d Missing flags in capture-pane, and tweak choose-tree text. From Dilyan Palauzov. 2016-10-14 17:40:47 +00:00
Thomas Adam
117737c6ca Merge branch 'obsd-master' 2016-10-14 02:01:14 +01:00
Thomas Adam
a7ce19347a Merge branch 'obsd-master' 2016-10-14 00:01:13 +01:00
nicm
4289a1ebfa Trying to do hooks generically is way too complicated and unreliable and
confusing, particularly trying to automatically figure out what target
hooks should be using. So simplify it:

- drop before hooks entirely, they don't seem to be very useful;

- commands with special requirements now fire their own after hook (for
  example, if they change session or window, or if they have -t and -s
  and need to choose which one the hook uses as current target);

- commands with no special requirements can have the CMD_AFTERHOOK flag
  added and they will use the -t state.

At the moment new-session, new-window, split-window fire their own hook,
and display-message uses the flag. The remaining commands still need to
be looked at.
2016-10-13 22:48:51 +00:00
Nicholas Marriott
5d2288b22a Update TODO. 2016-10-13 22:40:20 +01:00
nicm
7a1a01feef Remove the set-remain-on-exit option, it was always a hack and can now
be done with hooks instead.
2016-10-13 21:37:03 +00:00
Nicholas Marriott
e6f7180af1 tmux no longer uses openat() so we can remove the compatibilty function. 2016-10-13 22:17:29 +01:00
Thomas Adam
ad5a561adb Merge branch 'obsd-master' 2016-10-13 22:01:12 +01:00
nicm
4179b42424 Add support for BCE (background colour erase). This makes various escape
sequences (notable EL and ED but also IL, DL, ICH, DCH) create blank
cells using the current background colour rather than the default
colour.

On modern systems BCE doesn't really have many benefits, but most other
terminals now support it, some (lazy) applications rely on it, and it is
not hard to include now that we have pane background colours anyway.

Mostly written by Sean Haugh.
2016-10-13 20:27:27 +00:00
Nicholas Marriott
f691d46a16 Update TODO. 2016-10-13 21:14:33 +01:00
nicm
1bd08f903b Remove mention of key tables than no longer exist. 2016-10-13 20:09:19 +00:00
Thomas Adam
6270392d04 Merge branch 'obsd-master' 2016-10-13 12:01:11 +01:00
nicm
4d9e6ea310 Some improvements and bug fixes for hooks:
- Prepare the state again before the "after" hooks are run, because the
  command may have killed or moved windows.

- Use the hooks list from the newly prepared target, not the old hooks
  list (only matters for new-session really).

- Correctly detect an invalid current state and ignore it in
  cmd_find_target ("killw; swapw").

- Change neww, new, killp, killw, splitw, swapp, swapw to update the
  current state (used if no explicit target is given) to something more
  useful after they have finished. For example, neww changes it to the
  newly created window.

Hooks are still relatively new and primitive so there are likely to be
more changes to come.

Parts based on bug reports from Uwe Werler and Iblis Lin.
2016-10-13 10:01:49 +00:00
nicm
05dac2e42c -f missed from splitw usage, from Felix Rosencrantz. 2016-10-13 09:06:48 +00:00
Thomas Adam
6551f4bb3b Merge branch 'obsd-master'
Conflicts:
	paste.c
2016-10-13 08:09:47 +01:00
nicm
e0add119ea Compare to see if pane status line has actually changed, not just size, and
do not draw if pane is not visible.
2016-10-12 17:36:52 +00:00
nicm
e83ebf50de Fix a couple of problems with insert mode: flush dirty cells before we
modify the screen, not after; and use grid_view_insert_cells to make
space not grid_move_cells.
2016-10-12 15:43:51 +00:00
nicm
40253048ca bind-key -c has gone, remove from man page, and unused table declarations. 2016-10-12 15:26:37 +00:00
nicm
c484c5a2a1 Drop the edit mode key tables and just use fixed key bindings for the
command prompt.
2016-10-12 14:50:14 +00:00
nicm
4160df4ca4 Redraw selection in tty_draw_line, so it appears when redrawing whole
pane. Reported by Theo Buehler.
2016-10-12 13:24:07 +00:00
nicm
68bebe1fb7 The repeat prompt in both emacs and vi (and the old one in tmux) doesn't
support line editing and instead executes a command as soon as a
non-number key is pressed. Add a -N flag to command-prompt for the same
in copy mode. Reported by Theo Buehler.
2016-10-12 13:03:27 +00:00
Nicholas Marriott
76a9e6f27b NetBSD needs _OPENBSD_SOURCE for reallocarray. 2016-10-12 10:52:04 +01:00
nicm
22a8afee9e Unused variable and missing time.h. 2016-10-12 09:07:58 +00:00
Thomas Adam
12efb40dc5 Linux: #include <time.h> for time() 2016-10-12 09:53:30 +01:00
Thomas Adam
0f7d39c410 Add missing function protype 2016-10-12 09:49:16 +01:00
Thomas Adam
b9dc855016 Merge branch 'obsd-master'
Conflicts:
	format.c
	osdep-openbsd.c
2016-10-12 09:45:49 +01:00
nicm
5c49e1d0c1 Some other stuff that can be local to one file. 2016-10-11 13:45:47 +00:00
nicm
e45401846f Add static in window-*.c and move some internal functions out of tmux.h. 2016-10-11 13:21:59 +00:00
nicm
85d7afaefc Support double and triple clicks (they are cumulative, so double is
fired then triple), and use for select-word and select-line in copy
mode. Inspired by a different solution from Omar Sandoval.
2016-10-11 09:30:36 +00:00
nicm
76d6d3641f Fundamental change to how copy mode key bindings work:
The vi-copy and emacs-copy mode key tables are gone, and instead copy
mode commands are bound in one of two normal key tables ("copy-mode" or
"copy-mode-vi"). Keys are bound to "send-keys -X copy-mode-command". So:

    bind -temacs-copy C-Up scroll-up
    bind -temacs-copy -R5 WheelUpPane scroll-up

Becomes:

    bind -Tcopy-mode C-Up send -X scroll-up
    bind -Tcopy-mode WheelUpPane send -N5 -X scroll-up

This allows the full command parser and command set to be used - for
example, we can use the normal command prompt for searching, jumping,
and so on instead of a custom one:

    bind -Tcopy-mode C-r command-prompt -p'search up' "send -X search-backward '%%'"

command-prompt also gets a -1 option to only require on key press, which
is needed for jumping.

The plan is to get rid of mode keys entirely, so more to come eventually.
2016-10-11 07:23:34 +00:00
nicm
8b804fb589 Support UTF-8 entry into the command prompt. 2016-10-11 07:11:40 +00:00
nicm
a81685bfac Add static in cmd-* and fix a few other nits. 2016-10-10 21:51:39 +00:00
nicm
c426e485e5 Loads more static, except for cmd-*.c and window-*.c. 2016-10-10 21:29:23 +00:00
Thomas Adam
27126f8797 Merge branch 'obsd-master' 2016-10-10 20:01:11 +01:00
nicm
66b5477cc1 Do not allow the opposite pane to resize when dragging with the mouse
because it is not possible to keep the mouse on the border when the
minimum size is reached.
2016-10-10 17:28:30 +00:00
Thomas Adam
226b6a2192 Merge branch 'obsd-master' 2016-10-10 16:01:12 +01:00
nicm
7d4b416fe6 Some more static. 2016-10-10 13:54:47 +00:00
Thomas Adam
215d3f8c0d Merge branch 'obsd-master' 2016-10-09 18:01:10 +01:00
nicm
b8f2dd8237 Make the CLIENT_STATUS flag imply that pane status lines are redrawn if
they are enabled and break the actual screen generation code into a
separate function. Fixes problems reported by Romain Francoise.
2016-10-09 16:24:34 +00:00
Thomas Adam
526e860a7a Merge branch 'obsd-master' 2016-10-09 10:01:12 +01:00
nicm
1db6d6fea6 Pass file/line to new command for if-shell so that errors appear
sensibly.
2016-10-09 08:06:51 +00:00
nicm
48dd250af1 Handle NULL window or session for user options. 2016-10-09 07:58:35 +00:00
nicm
44449b305b Use xsnprintf not snprintf for the prompt in window_copy_write_line
because we don't care if it is truncated to the screen width, we don't
want it to be fatal.
2016-10-09 07:30:28 +00:00
Thomas Adam
fb0b2cd37a Merge branch 'obsd-master' 2016-10-06 00:01:11 +01:00
nicm
30086e504c screen_write_copy tried to be clever and clear the line if it reached
the end of the source, but it was wrong and causes problems that are
only showing up now we are more aggressive about skipping redundant
screen updates. Remove the optimization entirely as more trouble than it
is worth to fix (and it'll have to go when BCE is done anyway).
2016-10-05 22:00:29 +00:00
Thomas Adam
5b8f033e06 Merge branch 'obsd-master' 2016-10-05 14:01:10 +01:00
nicm
f55c991a1b Wrap some long lines in screen-write.c. 2016-10-05 12:36:36 +00:00
nicm
4117a7ed19 Keep buffer creation time and add accessors for it and the order number. 2016-10-05 12:34:05 +00:00
nicm
b4f95c43fc Allow cmd_mouse_at return arguments to be NULL. 2016-10-05 12:32:13 +00:00
Thomas Adam
4740ecbeae Merge branch 'obsd-master' 2016-10-04 02:01:11 +01:00
Thomas Adam
ddfed259f6 Merge branch 'obsd-master' 2016-10-04 00:01:11 +01:00
nicm
1b31d148c9 Remove some dead code in cmd-move-window.c and make a load of local
functions static.
2016-10-03 22:52:11 +00:00
Thomas Adam
6943fbbb81 Merge branch 'obsd-master' 2016-10-03 22:01:12 +01:00
nicm
305c832a97 Document set-hook -u. 2016-10-03 20:58:39 +00:00
nicm
61dfbe702e Remove some redundant checks and make ich/dch consistent. 2016-10-03 19:19:18 +00:00
Thomas Adam
23254f59da Fix typos 2016-09-30 09:50:40 +01:00
Thomas Adam
bb7cc8e8fd Start working on 2.4 2016-09-29 22:00:00 +01:00
240 changed files with 35266 additions and 17392 deletions

78
.github/CONTRIBUTING.md vendored Normal file
View File

@@ -0,0 +1,78 @@
## What should I do before opening an issue?
Before opening an issue, please ensure that:
- Your problem is a specific problem or question or suggestion, not a general
complaint.
- `$TERM` inside tmux is screen, screen-256color, tmux or tmux-256color. Check
by running `echo $TERM` inside tmux.
- You can reproduce the problem with the latest tmux release, or a build from
Git master.
- Your question or issue is not covered [in the
manual](https://man.openbsd.org/tmux.1) (run `man tmux`).
- Your problem is not mentioned in the [CHANGES
file](https://raw.githubusercontent.com/tmux/tmux/master/CHANGES) file.
- Nobody else has opened the same issue recently.
## What should I include in an issue?
Please include the output of:
~~~bash
uname -sp && tmux -V && echo $TERM
~~~
Also include:
- Your platform (Linux, OS X, or whatever).
- A brief description of the problem with steps to reproduce.
- A minimal tmux config, if you can't reproduce without a config.
- Your terminal, and `$TERM` inside and outside of tmux.
- Logs from tmux (see below).
- At most one or two screenshots, if helpful.
## How do I test without a .tmux.conf?
Run a separate tmux server with `-f/dev/null` to skip loading `.tmux.conf`:
~~~bash
tmux -Ltest kill-server
tmux -Ltest -f/dev/null new
~~~
## How do I get logs from tmux?
Add `-vv` to tmux to create three log files in the current directory. If you can
reproduce without a configuration file:
~~~bash
tmux -Ltest kill-server
tmux -vv -Ltest -f/dev/null new
~~~
Or if you need your configuration:
~~~base
tmux kill-server
tmux -vv new
~~~
The log files are:
- `tmux-server*.log`: server log file.
- `tmux-client*.log`: client log file.
- `tmux-out*.log`: output log file.
Please attach the log files to your issue.

22
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,22 @@
### Issue description
Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
before opening an issue.
If you have upgraded, make sure your issue is not covered in the CHANGES file
for your version: https://raw.githubusercontent.com/tmux/tmux/master/CHANGES
Describe the problem and the steps to reproduce. Add a minimal tmux config if
necessary. Screenshots can be helpful, but no more than one or two.
Do not report bugs (crashes, incorrect behaviour) without reproducing on a tmux
built from the latest code in Git.
### Required information
Please provide the following information:
* tmux version (`tmux -V`).
* Platform (`uname -sp`).
* $TERM inside and outside of tmux (`echo $TERM`).
* Logs from tmux (`tmux kill-server; tmux -vv new`).

83
.github/README.md vendored Normal file
View File

@@ -0,0 +1,83 @@
# Welcome to tmux!
tmux is a terminal multiplexer: it enables a number of terminals to be created,
accessed, and controlled from a single screen. tmux may be detached from a
screen and continue running in the background, then later reattached.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
## Dependencies
tmux depends on [libevent](https://libevent.org) 2.x, available from [this
page](https://github.com/libevent/libevent/releases/latest).
It also depends on [ncurses](https://www.gnu.org/software/ncurses/), available
from [this page](https://invisible-mirror.net/archives/ncurses/).
## Installation
### From release tarball
To build and install tmux from a release tarball, use:
~~~bash
./configure && make
sudo make install
~~~
tmux can use the utempter library to update utmp(5), if it is installed - run
configure with `--enable-utempter` to enable this.
### From version control
To get and build the latest from version control - note that this requires
`autoconf`, `automake` and `pkg-config`:
~~~bash
git clone https://github.com/tmux/tmux.git
cd tmux
sh autogen.sh
./configure && make
~~~
## Contributing
Bug reports, feature suggestions and especially code contributions are most
welcome. Please send by email to:
tmux-users@googlegroups.com
Or open a GitHub issue or pull request. **Please read [this
document](CONTRIBUTING.md) before opening an issue.**
There is [a list of suggestions for contributions](https://github.com/tmux/tmux/wiki/Contributing).
Please feel free to ask on the mailing list if you're thinking of working on something or need
further information.
## Documentation
For documentation on using tmux, see the tmux.1 manpage. View it from the
source tree with:
~~~bash
nroff -mdoc tmux.1|less
~~~
A small example configuration is in `example_tmux.conf`.
And a bash(1) completion file at:
https://github.com/imomaliev/tmux-bash-completion
For debugging, run tmux with `-v` or `-vv` to generate server and client log
files in the current directory.
## Support
The tmux mailing list for general discussion and bug reports is:
https://groups.google.com/forum/#!forum/tmux-users
Subscribe by sending an email to:
tmux-users+subscribe@googlegroups.com

1
.gitignore vendored
View File

@@ -18,3 +18,4 @@ Makefile.in
configure configure
tmux.1.* tmux.1.*
*.dSYM *.dSYM
cmd-parse.c

View File

@@ -1,10 +1,16 @@
language: c language: c
matrix:
include: os:
- compiler: gcc - linux
- compiler: clang - osx
env: CFLAGS="-g -O2"
compiler:
- gcc
- clang
before_install: before_install:
- sudo apt-get update -qq - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq; fi
- sudo apt-get -y install debhelper autotools-dev dh-autoreconf file libncurses5-dev libevent-dev pkg-config libutempter-dev build-essential - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -y install bison autotools-dev libncurses5-dev libevent-dev pkg-config libutempter-dev build-essential; fi
script: (CFLAGS= ./autogen.sh) && ./configure --enable-debug && make
script:
- ./autogen.sh && ./configure && make

669
CHANGES
View File

@@ -1,4 +1,646 @@
CHANGES FROM 2.2 to 2.3 29 September 2016 CHANGES FROM 3.0 to 3.0a
* Do not require REG_STARTEND.
* Respawn panes or windows correctly if default-command is set.
* Add missing option for after-kill-pane hook.
* Fix for crash with a format variable that doesn't exist.
* Do not truncate list-keys output on some platforms.
* Do not crash when restoring a layout with only one pane.
CHANGES FROM 2.9 to 3.0
* Workaround invalid layout strings generated by older tmux versions and add
some additional sanity checks
* xterm 348 now disables margins when resized, so send DECLRMM again after
resize.
* Add support for the SD (scroll down) escape sequence.
* Expand arguments to C and s format modifiers to match the m modifier.
* Add support for underscore colours (Setulc capability must be added with
terminal-overrides as described in tmux(1)).
* Add a "fill" style attribute for the fill colour of the drawing area (where
appropriate).
* New -H flag to send-keys to send literal keys.
* Format variables for pane mouse modes (mouse_utf8_flag and mouse_sgr_flag)
and for origin mode (origin_flag).
* Add -F to refresh-client for flags for control mode clients, only one flag
(no-output) supported at the moment.
* Add a few vi(1) keys for menus.
* Add pane options, set with set-option -p and displayed with show-options -p.
Pane options inherit from window options (so every pane option is also
a window option). The pane style is now configured by setting window-style
and window-active-style in the pane options; select-pane -P and -g now change
the option but are no longer documented.
* Do not document set-window-option and show-window-options. set-option -w and
show-options -w should be used instead.
* Add a -A flag to show-options to show parent options as well (they are marked
with a *).
* Resize panes lazily - do not resize unless they are in an attached, active
window.
* Add regular expression support for the format search, match and substitute
modifiers and make them able to ignore case. find-window now accepts -r to
use regular expressions.
* Do not use $TMUX to find the session because for windows in multiple sessions
it is wrong as often as it is right, and for windows in one session it is
pointless. Instead use TMUX_PANE if it is present.
* Do not always resize the window back to its original size after applying a
layout, keep it at the layout size until it must be resized (for example when
attached and window-size is not manual).
* Add new-session -X and attach-session -x to send SIGHUP to parent when
detaching (like detach-client -P).
* Support for octal escapes in strings (such as \007) and improve list-keys
output so it parses correctly if copied into a configuration file.
* INCOMPATIBLE: Add a new {} syntax to the configuration file. This is a string
similar to single quotes but also includes newlines and allows commands that
take other commands as string arguments to be expressed more clearly and
without additional escaping.
A literal { and } or a string containing { or } must now be escaped or
quoted, for example '{' and '}' instead of { or }, or 'X#{foo}' instead of
X#{foo}.
* New <, >, <= and >= comparison operators for formats.
* Improve escaping of special characters in list-keys output.
* INCOMPATIBLE: tmux's configuration parsing has changed to use yacc(1). There
is one incompatible change: a \ on its own must be escaped or quoted as
either \\ or '\' (the latter works on older tmux versions).
Entirely the same parser is now used for parsing the configuration file
and for string commands. This means that constructs previously only
available in .tmux.conf, such as %if, can now be used in string commands
(for example, those given to if-shell - not commands invoked from the
shell, they are still parsed by the shell itself).
* Add support for the overline attribute (SGR 53). The Smol capability is
needed in terminal-overrides.
* Add the ability to create simple menus. Introduces new command
display-menu. Default menus are bound to MouseDown3 on the status line;
MouseDown3 or M-MouseDown3 on panes; MouseDown3 in tree, client and
buffer modes; and C-b C-m and C-b M-m.
* Allow panes to be empty (no command). They can be created either by piping to
split-window -I, or by passing an empty command ('') to split-window. Output
can be sent to an existing empty window with display-message -I.
* Add keys to jump between matching brackets (emacs C-M-f and C-M-b, vi %).
* Add a -e flag to new-window, split-window, respawn-window, respawn-pane to
pass environment variables into the newly created process.
* Hooks are now stored in the options tree as array options, allowing them to
have multiple separate commands. set-hook and show-hooks remain but
set-option and show-options can now also be used (show-options will only show
hooks if given the -H flag). Hooks with multiple commands are run in index
order.
* Automatically scroll if dragging to create a selection with the mouse and the
cursor reaches the top or bottom line.
* Add -no-clear variants of copy-selection and copy-pipe which do not clear the
selection after copying. Make copy-pipe clear the selection by default to be
consistent with copy-selection.
* Add an argument to copy commands to set the prefix for the buffer name, this
(for example) allows buffers for different sessions to be named separately.
* Update session activity on focus event.
* Pass target from source-file into the config file parser so formats in %if
and %endif have access to more useful variables.
* Add the ability to infer an option type (server, session, window) from its
name to show-options (it was already present in set-option).
CHANGES FROM 2.9 to 2.9a
* Fix bugs in select-pane and the main-horizontal and main-vertical layouts.
CHANGES FROM 2.8 to 2.9
* Attempt to preserve horizontal cursor position as well as vertical with
reflow.
* Rewrite main-vertical and horizontal and change layouts to better handle the
case where all panes won't fit into the window size, reduce problems with
pane border status lines and fix other bugs mostly found by Thomas Sattler.
* Add format variables for the default formats in the various modes
(tree_mode_format and so on) and add a -a flag to display-message to list
variables with values.
* Add a -v flag to display-message to show verbose messages as the format is
parsed, this allows formats to be debugged
* Add support for HPA (\033[`).
* Add support for origin mode (\033[?6h).
* No longer clear history on RIS.
* Extend the #[] style syntax and use that together with previous format
changes to allow the status line to be entirely configured with a single
option.
Now that it is possible to configure their content, enable the existing code
that lets the status line be multiple lines in height. The status option can
now take a value of 2, 3, 4 or 5 (as well as the previous on or off) to
configure more than one line. The new status-format array option configures
the format of each line, the default just references the existing status-*
options, although some of the more obscure status options may be eliminated
in time.
Additions to the #[] syntax are: "align" to specify alignment (left, centre,
right), "list" for the window list and "range" to configure ranges of text
for the mouse bindings.
The "align" keyword can also be used to specify alignment of entries in tree
mode and the pane status lines.
* Add E: and T: format modifiers to expand a format twice (useful to expand the
value of an option).
* The individual -fg, -bg and -attr options have been removed; they
were superseded by -style options in tmux 1.9.
* Allow more than one mode to be opened in a pane. Modes are kept on a stack
and retrieved if the same mode is entered again. Exiting the active mode goes
back to the previous one.
* When showing command output in copy mode, call it view mode instead (affects
pane_mode format).
* Add -b to display-panes like run-shell.
* Handle UTF-8 in word-separators option.
* New "terminal" colour allowing options to use the terminal default colour
rather than inheriting the default from a parent option.
* Do not move the cursor in copy mode when the mouse wheel is used.
* Use the same working directory rules for jobs as new windows rather than
always starting in the user's home.
* Allow panes to be one line or column in size.
* Go to last line when goto-line number is out of range in copy mode.
* Yank previously cut text if any with C-y in the command prompt, only use the
buffer if no text has been cut.
* Add q: format modifier to quote shell special characters.
* Add StatusLeft and StatusRight mouse locations (keys such as
MouseDown1StatusLeft) for the status-left and status-right areas of the
status line.
* Add -Z to find-window.
* Support for windows larger than the client. This adds two new options,
window-size and default-size, and a new command, resize-window. The
force-width and force-height options and the session_width and session_height
formats have been removed.
The new window-size option tells tmux how to work out the size of windows:
largest means it picks the size of the largest session, smallest the smallest
session (similar to the old behaviour) and manual means that it does not
automatically resize windows. aggressive-resize modifies the choice of
session for largest and smallest as it did before.
If a window is in a session attached to a client that is too small, only part
of the window is shown. tmux attempts to keep the cursor visible, so the part
of the window displayed is changed as the cursor moves (with a small delay,
to try and avoid excess redrawing when applications redraw status lines or
similar that are not currently visible).
Drawing windows which are larger than the client is not as efficient as those
which fit, particularly when the cursor moves, so it is recommended to avoid
using this on slow machines or networks (set window-size to smallest or
manual).
The resize-window command can be used to resize a window manually. If it is
used, the window-size option is automatically set to manual for the window
(undo this with "setw -u window-size"). resize-window works in a similar way
to resize-pane (-U -D -L -R -x -y flags) but also has -a and -A flags. -a
sets the window to the size of the smallest client (what it would be if
window-size was smallest) and -A the largest.
For the same behaviour as force-width or force-height, use resize-window -x
or -y.
If the global window-size option is set to manual, the default-size option is
used for new windows. If -x or -y is used with new-session, that sets the
default-size option for the new session.
The maximum size of a window is 10000x10000. But expect applications to
complain and higher memory use if making a window that big. The minimum size
is the size required for the current layout including borders.
The refresh-client command can be used to pan around a window, -U -D -L -R
moves up, down, left or right and -c returns to automatic cursor
tracking. The position is reset when the current window is changed.
CHANGES FROM 2.7 to 2.8
* Make display-panes block the client until a pane is chosen or it
times out.
* Clear history on RIS like most other terminals do.
* Add an "Any" key to run a command if a key is pressed that is not
bound in the current key table.
* Expand formats in load-buffer and save-buffer.
* Add a rectangle_toggle format.
* Add set-hook -R to run a hook immediately.
* Add README.ja.
* Add pane focus hooks.
* Allow any punctuation as separator for s/x/y not only /.
* Improve resizing with the mouse (fix resizing the wrong pane in some
layouts, and allow resizing multiple panes at the same time).
* Allow , and } to be escaped in formats as #, and #}.
* Add KRB5CCNAME to update-environment.
* Change meaning of -c to display-message so the client is used if it
matches the session given to -t.
* Fixes to : form of SGR.
* Add x and X to choose-tree to kill sessions, windows or panes.
CHANGES FROM 2.6 TO 2.7
* Remove EVENT_* variables from environment on platforms where tmux uses them
so they do not pass on to panes.
* Fixes for hooks at server exit.
* Remove SGR 10 (was equivalent to SGR 0 but no other terminal seems to do
this).
* Expand formats in window and session names.
* Add -Z flag to choose-tree, choose-client, choose-buffer to automatically
zoom the pane when the mode is entered and unzoom when it exits, assuming the
pane is not already zoomed. This is now part of the default key bindings.
* Add C-g to exit modes with emacs keys.
* Add exit-empty option to exit server if no sessions (defaults to on).
* Show if a filter is present in choose modes.
* Add pipe-pane -I to to connect stdin of the child process.
* Performance improvements for reflow.
* Use RGB terminfo(5) capability to detect RGB colour terminals (the existing
Tc extension remains unchanged).
* Support for ISO colon-separated SGR sequences.
* Add select-layout -E to spread panes out evenly (bound to E key).
* Support wide characters properly when reflowing.
* Pass PWD to new panes as a hint to shells, as well as calling chdir().
* Performance improvements for the various choose modes.
* Only show first member of session groups in tree mode (-G flag to choose-tree
to show all).
* Support %else in config files to match %if; from Brad Town in GitHub issue
1071.
* Fix "kind" terminfo(5) capability to be S-Down not S-Up.
* Add a box around the preview label in tree mode.
* Show exit status and time in the remain-on-exit pane text; from Timo
Boettcher in GitHub issue 1103.
* Correctly use pane-base-index in tree mode.
* Change the allow-rename option default to off.
* Support for xterm(1) title stack escape sequences (GitHub issue 1075 from
Brad Town).
* Correctly remove padding cells to fix a UTF-8 display problem (GitHub issue
1090).
CHANGES FROM 2.5 TO 2.6, 05 October 2017
* Add select-pane -T to set pane title.
* Fix memory leak when lines with BCE are removed from history.
* Fix (again) the "prefer unattached" behaviour of attach-session.
* Reorder how keys are checked to allow keys to be specified that have a
leading escape. GitHub issue 1048.
* Support REP escape sequence (\033[b).
* Run alert hooks based on options rather than always, and allow further bells
even if there is an existing bell.
* Add -d flag to display-panes to override display-panes-time.
* Add selection_present format when in copy mode (allows key bindings that do
something different if there is a selection).
* Add pane_at_left, pane_at_right, pane_at_top and pane_at_bottom formats.
* Make bell, activity and silence alerting more consistent by: removing the
bell-on-alert option; adding activity-action and silence-action options with
the same possible values as the existing bell-action; adding a "both" value
for the visual-bell, visual-activity and visual-silence options to trigger
both a bell and a message.
* Add a pane_pipe format to show if pipe-pane is active.
* Block signals between forking and resetting signal handlers so that the
libevent signal handler doesn't get called in the child and incorrectly write
into the signal pipe that it still shares with the parent. GitHub issue 1001.
* Allow punctuation in pane_current_command.
* Add -c for respawn-pane and respawn-window.
* Wait for any remaining data to flush when a pane is closed while pipe-pane is
in use.
* Fix working out current client with no target. GitHub issue 995.
* Try to fallback to C.UTF-8 as well as en_US.UTF-8 when looking for a UTF-8
locale.
* Add user-keys option for user-defined key escape sequences (mapped to User0
to User999 keys).
* Add pane-set-clipboard hook.
* FAQ file has moved out of repository to online.
* Fix problem with high CPU usage when a client dies unexpectedly. GitHub issue
941.
* Do a dance on OS X 10.10 and above to return tmux to the user namespace,
allowing access to the clipboard.
* Do not allow escape sequences which expect a specific terminator (APC, DSC,
OSC) to wait for forever - use a small timeout. This reduces the chance of
the pane locking up completely when sent garbage (cat /dev/random or
similar).
* Support SIGUSR2 to toggle logging on a running server, also generate the
"out" log file with -vv not -vvvv.
* Make set-clipboard a three state option: on (tmux both sends to outside
terminal and accepts from applications inside); external (tmux sends outside
but does not accept inside); and off.
* Fix OSC 4 palette setting for bright foreground colours. GitHub issue 954.
* Use setrgbf and setrgbb terminfo(5) capabilities to set RGB colours, if they
are available. (Tc is still supported as well.)
* Fix redrawing panes when they are resized several times but end up with the
size unchanged (for example, splitw/resizep -Z/breakp).
* Major rewrite of choose mode. Now includes preview, sorting, searching and
tagging; commands that can be executed directly from the mode (for example,
to delete one or more buffers); and filtering in tree mode.
* choose-window and choose-session are now aliases of choose-tree (in the
command-alias option).
* Support OSC 10 and OSC 11 to set foreground and background colours.
* Check the U8 capability to determine whether to use UTF-8 line drawing
characters for ACS.
* Some missing notifications for layout changes.
* Control mode clients now do not affect session sizes until they issue
refresh-client -C. new-session -x and -y works with control clients even if
the session is not detached.
* All new sessions that are unattached (whether with -d or started with no
terminal) are now created with size 80 x 24. Whether the status line is on or
off does not affect the size of new sessions until they are attached.
* Expand formats in option names and add -F flag to expand them in option values.
* Remember the search string for a pane even if copy mode is exited and entered
again.
* Some further BCE fixes (scroll up, reverse index).
* Improvements to how terminals are cleared (entirely or partially).
CHANGES FROM 2.4 TO 2.5, 09 May 2017
* Reset updated flag when restarting #() command so that new output is properly
recognised. GitHub issue 922.
* Fix ECH with a background colour.
* Do not rely on the terminal not moving the cursor after DL or EL.
* Fix send-keys and send-prefix in copy-mode (so C-b C-b works). GitHub issue
905.
* Set the current pane for rotate-window so it works in command sequences.
* Add pane_mode format.
* Differentiate M-Up from Escape+Up when possible (that is, in terminals with
xterm(1) style function keys). GitHub issue 907.
* Add session_stack and window_stack_index formats.
* Some new control mode notifications and corresponding hooks:
pane-mode-changed, window-pane-changed, client-session-changed,
session-window-changed.
* Format pane_search_string for last search term while in copy mode (useful
with command-prompt -I).
* Fix a problem with high CPU usage and multiple clients with #(). GitHub issue
889.
* Fix UTF-8 combining characters in column 0.
* Fix reference counting so that panes are properly destroyed and their
processes killed.
* Clamp SU (CSI S) parameter to work around a bug in Konsole.
* Tweak line wrapping in full width panes to play more nicely with terminal
copy and paste.
* Fix when we emit SGR 0 in capture-pane -e.
* Do not change TERM until after config file parsing has finished, so that
commands run inside the config file can use it to make decisions (typically
about default-terminal).
* Make the initial client wait until config file parsing has finished to avoid
racing with commands.
* Fix core when if-shell fails.
* Only use ED to clear screen if the pane is at the bottom.
* Fix multibyte UTF-8 output.
* Code improvements around target (-t) resolution.
* Change how the default target (for commands without -t) is managed across
command sequences: now it is set up at the start and commands are required
to update it if needed. Fixes binding command sequences to mouse keys.
* Make if-shell from the config file work correctly.
* Change to always check the root key table if no binding is found in the
current table (prefix table or copy-mode table or whatever). This means that
root key bindings will take effect even in copy mode, if not overridden by a
copy mode key binding.
* Fix so that the history file works again.
* Run config file without a client rather than using the first client, restores
previous behaviour.
* If a #() command doesn't exit, continue to read from it and use its last full
line of output.
* Handle slow terminals and fast output better: when the amount of data
outstanding gets too large, discard output until it is drained and we are
able to do a full redraw. Prevents tmux sitting on a huge buffer that the
terminal will take forever to consume.
* Do not redraw a client unless we realistically think it can accept the data -
defer redraws until the client has nothing else waiting to write.
CHANGES FROM 2.3 TO 2.4, 20 April 2017
Incompatible Changes
====================
* Key tables have undergone major changes. Mode key tables are no longer
separate from the main key tables. All mode key tables have been removed,
together with the -t flag to bind-key and unbind-key.
The emacs-edit, vi-edit, emacs-choose and vi-choose tables have been replaced
by fixed key bindings in the command prompt and choose modes. The mode-keys
and status-keys options remain.
The emacs-copy and vi-copy tables have been replaced by the copy-mode and
copy-mode-vi tables. Commands are sent using the -X and -N flags to
send-keys. So the following:
bind -temacs-copy C-Up scroll-up
bind -temacs-copy -R5 WheelUpPane scroll-up
Becomes:
bind -Tcopy-mode C-Up send -X scroll-up
bind -Tcopy-mode WheelUpPane send -N5 -X scroll-up
These changes allows the full command parser (including command sequences) and
command set to be used - for example, the normal command prompt with editing
and history is now used for searching, jumping, and so on instead of a custom
one. The default C-r binding is now:
bind -Tcopy-mode C-r command-prompt -i -p'search up' "send -X search-backward-incremental '%%'"
There are also some new commmands available with send -X, such as
copy-pipe-and-cancel.
* set-remain-on-exit has gone -- can be achieved with hooks instead.
* Hooks: before hooks have been removed and only a selection of commands now
have after hooks (they are no longer automatic). Additional hooks have been
added.
* The xterm-keys option now defaults to on.
Normal Changes
==============
* Support for mouse double and triple clicks.
* BCE (Background Colour Erase) is now supported.
* All occurrences of a search string in copy mode are now highlighted;
additionally, the number of search results is displayed. The highlighting
updates interactively with the default emacs key bindings (incremental
search).
* source-file now understands glob patterns.
* Formats now have simple comparisons:
#{==:a,b}
#{!=:a,b}
* There are the following new formats:
- #{version} -- the tmux server version;
- #{client_termtype} -- the terminal type of the client;
- #{client_name} -- the name of a client;
- #{client_written} -- the number of bytes written to the client.
* The configuration file now accepts %if/%endif conditional blocks which are
processed when it is parsed; the argument is a format string (useful with the
new format comparison options).
* detach-client now has -E to execute a command replacing the client instead of
exiting.
* Add support for custom command aliases, this is an array option which
contains items of the form "alias=command". This is consulted when an
unknown command is parsed.
* break-pane now has -n to specify the new window name.
* OSC 52 support has been added for programs inside tmux to set a tmux buffer.
* The mouse "all event" mode (1003) is now supported.
* Palette setting is now possible (OSC 4 and 104).
* Strikethrough support (a recent terminfo is required).
* Grouped sessions can now be named (new -t).
* terminal-overrides and update-environment are now array options (the previous
set -ag syntax should work without change).
* There have been substantial performance improvements.
CHANGES FROM 2.2 TO 2.3, 29 September 2016
Incompatible Changes Incompatible Changes
==================== ====================
@@ -8,9 +650,9 @@ None.
Normal Changes Normal Changes
============== ==============
* New option 'pane-border-status' to add text in the oane borders. * New option 'pane-border-status' to add text in the pane borders.
* Support for hooks on commands: 'after' and 'before' hooks. * Support for hooks on commands: 'after' and 'before' hooks.
* 'source-file' understands '-q' to supress errors for nonexistent files. * 'source-file' understands '-q' to suppress errors for nonexistent files.
* Lots of UTF8 improvements, especially on MacOS. * Lots of UTF8 improvements, especially on MacOS.
* 'window-status-separator' understands #[] expansions. * 'window-status-separator' understands #[] expansions.
* 'split-window' understands '-f' for performing a full-width split. * 'split-window' understands '-f' for performing a full-width split.
@@ -19,7 +661,7 @@ Normal Changes
* 'display-panes' can now accept a command to run, rather than always * 'display-panes' can now accept a command to run, rather than always
selecting the pane. selecting the pane.
CHANGES FROM 2.1 to 2.2 10 April 2016 CHANGES FROM 2.1 TO 2.2, 10 April 2016
Incompatible Changes Incompatible Changes
==================== ====================
@@ -31,7 +673,7 @@ Incompatible Changes
can be used. can be used.
* Support for TMPDIR has been removed. Use TMUX_TMPDIR instead. * Support for TMPDIR has been removed. Use TMUX_TMPDIR instead.
* UTF8 detection how happens automatically if the client supports it, hence * UTF8 detection now happens automatically if the client supports it, hence
the: the:
mouse-utf8 mouse-utf8
@@ -84,8 +726,7 @@ Normal Changes
* RGB (24bit) colour support. The 'Tc' flag must be set in the external TERM * RGB (24bit) colour support. The 'Tc' flag must be set in the external TERM
entry (using terminal-overrides or a custom terminfo entry). entry (using terminal-overrides or a custom terminfo entry).
CHANGES FROM 2.0 TO 2.1, 18 October 2015
CHANGES FROM 2.0 to 2.1 18 October 2015
Incompatible Changes Incompatible Changes
==================== ====================
@@ -136,7 +777,7 @@ Normal Changes
* Copy mode is exited if the history is cleared whilst in copy-mode. * Copy mode is exited if the history is cleared whilst in copy-mode.
* 'copy-mode' learned '-e' to exit copy-mode when scrolling to end. * 'copy-mode' learned '-e' to exit copy-mode when scrolling to end.
CHANGES FROM 1.9a to 2.0 6 March 2015 CHANGES FROM 1.9a TO 2.0, 06 March 2015
Incompatible Changes Incompatible Changes
==================== ====================
@@ -195,9 +836,9 @@ Normal Changes
* 'split-window' and 'join-window' understand -b to create the pane to the left * 'split-window' and 'join-window' understand -b to create the pane to the left
or above the target pane. or above the target pane.
CHANGES FROM 1.9 to 1.9a 22 February 2014 CHANGES FROM 1.9 TO 1.9a, 22 February 2014
NOTE: This is a bug-fix release to address some important bugs which just NOTE: This is a bug-fix release to address some important bugs which just
missed the 1.9 deadline, but were found afterwards. missed the 1.9 deadline, but were found afterwards.
Normal Changes Normal Changes
@@ -206,7 +847,7 @@ Normal Changes
* Fix crash due to uninitialized lastwp member of layout_cell * Fix crash due to uninitialized lastwp member of layout_cell
* Fix -fg/-bg/-style with 256 colour terminals. * Fix -fg/-bg/-style with 256 colour terminals.
CHANGES FROM 1.8 to 1.9, 20 February 2014 CHANGES FROM 1.8 TO 1.9, 20 February 2014
NOTE: This release has bumped the tmux protocol version. It is therefore NOTE: This release has bumped the tmux protocol version. It is therefore
advised that the prior tmux server is restarted when this version of tmux is advised that the prior tmux server is restarted when this version of tmux is
@@ -261,7 +902,7 @@ Normal Changes
* tmux now supports 256 colours running under fbterm. * tmux now supports 256 colours running under fbterm.
* Many bug fixes! * Many bug fixes!
CHANGES FROM 1.7 to 1.8, 26 March 2013 CHANGES FROM 1.7 TO 1.8, 26 March 2013
Incompatible Changes Incompatible Changes
==================== ====================
@@ -312,7 +953,7 @@ Normal Changes
* Lots and lots of bug fixes, fixing memory-leaks, etc. * Lots and lots of bug fixes, fixing memory-leaks, etc.
* Various manpage improvements. * Various manpage improvements.
CHANGES FROM 1.6 to 1.7, 13 October 2012 CHANGES FROM 1.6 TO 1.7, 13 October 2012
* tmux configuration files now support line-continuation with a "\" at the * tmux configuration files now support line-continuation with a "\" at the
end of a line. end of a line.
@@ -703,7 +1344,7 @@ CHANGES FROM 1.0 TO 1.1, 05 November 2009
* xterm-keys rewrite. * xterm-keys rewrite.
* Additional code reduction, and bug fixes. * Additional code reduction, and bug fixes.
CHANGES FROM 0.9 TO 1.0, 20 Sept 2009 CHANGES FROM 0.9 TO 1.0, 20 September 2009
* Option to alter the format of the window title set by tmux. * Option to alter the format of the window title set by tmux.
* Backoff for a while after multiple incorrect password attempts. * Backoff for a while after multiple incorrect password attempts.

View File

@@ -1,10 +1,7 @@
THIS IS FOR INFORMATION ONLY, CODE IS UNDER THE LICENCE AT THE TOP OF ITS FILE. THIS IS FOR INFORMATION ONLY, CODE IS UNDER THE LICENCE AT THE TOP OF ITS FILE.
The README, CHANGES, FAQ and TODO files are licensed under the ISC The README, CHANGES, FAQ and TODO files are licensed under the ISC license. All
license. Files under examples/ remain copyright their authors unless otherwise other files have a license and copyright notice at their start, typically:
stated in the file but permission has been received to distribute them with
tmux. All other files have a license and copyright notice at their start,
typically:
Copyright (c) <author> Copyright (c) <author>

454
FAQ
View File

@@ -1,454 +0,0 @@
tmux frequently asked questions
******************************************************************************
* PLEASE NOTE: most display problems are due to incorrect TERM! Before *
* reporting problems make SURE that TERM settings are correct inside and *
* outside tmux. *
* *
* Inside tmux TERM must be "screen" or similar (such as "screen-256color"). *
* Don't bother reporting problems where it isn't! *
* *
* Outside, it must match your terminal: particularly, use "rxvt" for rxvt *
* and derivatives. *
******************************************************************************
* How is tmux different from GNU screen?
tmux and GNU screen have many similarities. Some of the main differences I am
aware of are (bearing in mind I haven't used screen for a few years now):
- tmux uses a client-server model. Each server has single Unix domain socket in
/tmp and within one server there are multiple sessions which may be attached
to multiple clients (terminals).
This has advantages, notably: windows may be linked simultaneously to
multiple sessions; windows may be moved freely between sessions; and a client
may be switched between sessions easily (C-b D). There is one major
disadvantage: if the server crashes, game over, all sessions die. In
practice, however, tmux is quite stable and gets more so as people report any
bugs they hit :-).
This model is different from screen, where typically each new screen instance
is independent. tmux supports the same behaviour by using multiple servers
with the -L option but it is not typically recommended.
- Different command interfaces. One of the goals of tmux is that the shell
should be easily usable as a scripting language - almost all tmux commands
can be used from the shell and behave identically whether used from the
shell, from a key binding or from the command prompt. Personally I also find
tmux's command interface much more consistent and clearer, but this is
subjective.
- tmux calls window names (what you see in the status line) "names", screen
calls them "titles".
- tmux has a multiple paste buffers. Not a major one but comes in handy quite a
lot.
- tmux supports automatically renaming windows to the running application
without gross hacks using escape sequences. Its even on by default.
- tmux has a choice of vi or emacs key layouts. Again, not major, but I use
emacs so if tmux did support only one key set it would be emacs and then all
the vi users would get humpy. Key bindings may be completely reconfigured in
any case.
- tmux has an option to limit the window size.
- tmux has search in windows (C-b f).
- The window split (pane) model is different. tmux has two objects, windows and
panes; screen has just windows. This difference has several implications:
* In screen you can have a window appear in several layouts, in tmux a pane
can only be in one window (fixing this is a big todo item but quite
invasive).
* tmux layouts are immutable and do not get changed unless you modify them.
* In tmux, all panes are closed when you kill a window.
* tmux panes do not have individual names, titles and so on.
I think tmux's model is much easier to manage and navigate within a window,
but breaking panes off from and joining them to windows is more clumsy.
tmux also has support for preset pane layouts.
- tmux's status line syntax is more readable and easier to use. I think it'd be
hard for anyone to argue with this. tmux doesn't support running a command
constantly and always using the last line of its output, commands must be run
again each time.
- tmux has modern, easily extended code. Again hard to argue screen is better
if you have looked at the code.
- tmux depends on libevent. I don't see this as a disadvantage: libevent is
small and portable, and on modern systems with current package management
systems dependencies are not an issue. libevent brings advantages in code
simplicity and performance.
- screen allows the window to be bigger than the terminal and can pan around
it. tmux limits the size to the largest attached client. This is a big todo
item for tmux but it is not trivial.
- screen has builtin serial and telnet support; this is bloat and is unlikely
to be added to tmux.
- Environment handling is different.
- tmux tends to be more demanding on the terminal so tends to show up terminal
and application bugs which screen does not.
- screen has wider platform support, for example IRIX, and for odd terminals.
* I found a bug! What do I do?
Check the latest version of tmux from Git to see if the problem is still
reproducible. Sometimes the length of time between releases means a lot of
fixes can be sitting in Git and the problem might already be fixed.
Please send bug reports by email to nicholas.marriott@gmail.com or
tmux-users@googlegroups.com. Please include as much of the following
information as possible:
- the version of tmux you are running;
- the operating system you are using and its version;
- the terminal emulator you are using and the TERM setting when tmux was
started;
- a description of the problem;
- if the problem is repeatable, the steps to repeat the problem;
- for screen corruption issues, a screenshot and the output of "infocmp $TERM"
from outside tmux are often very useful.
* Why doesn't tmux do $x?
Please send feature requests by email to tmux-users@googlegroups.com.
* Why do you use the screen terminal description inside tmux? It sucks.
It is already widely available. It is planned to change to something else such
as xterm-xfree86 at some point, if possible.
* I don't see any colour in my terminal! Help!
On some platforms, common terminal descriptions such as xterm do not include
colour. screen ignores this, tmux does not. If the terminal emulator in use
supports colour, use a value for TERM which correctly lists this, such as
xterm-color.
* tmux freezes my terminal when I attach to a session. I even have to kill -9
the shell it was started from to recover!
Some consoles really really don't like attempts to set the window title. Tell
tmux not to do this by turning off the "set-titles" option (you can do this
in .tmux.conf):
set -g set-titles off
If this doesn't fix it, send a bug report.
* Why is C-b the prefix key? How do I change it?
The default key is C-b because the prototype of tmux was originally developed
inside screen and C-b was chosen not to clash with the screen meta key. It
also has the advantage of not interfering with the use of C-a for start-of-line
in emacs and the shell (although it does interfere with previous-character).
Changing is simple: change the "prefix-key" option, and - if required - move
the binding of the "send-prefix" command from C-b (C-b C-b sends C-b by
default) to the new key. For example:
set -g prefix C-a
unbind C-b
bind C-a send-prefix
* How do I use UTF-8?
When running tmux in a UTF-8 capable terminal, UTF-8 must be turned on in tmux;
as of release 0.9, tmux attempts to autodetect a UTF-8-capable terminal by
checking the LC_ALL, LC_CTYPE and LANG environment variables. list-clients may
be used to check if this is detected correctly; if not, the -u command-line
flag may be specified when creating or attaching a client to a tmux session:
$ tmux -u new
Since the 1.0 release, tmux will turn on UTF-8 related options automatically
(ie status-utf8, and utf8) if the above conditions are met.
* How do I use a 256 colour terminal?
Provided the underlying terminal supports 256 colours, it is usually sufficient
to add the following to ~/.tmux.conf:
set -g default-terminal "screen-256color"
Note that some platforms do not support "screen-256color" ("infocmp
screen-256color" will return an error) - in this case see the next entry in
this FAQ.
tmux attempts to detect a 256 colour terminal both by looking at the colors
terminfo entry and by looking for the string "256col" in the TERM environment
variable.
If both these methods fail, the -2 flag may be passed to tmux when attaching
to a session to indicate the terminal supports 256 colours.
* vim or $otherprogram doesn't display 256 colours. What's up?
Some programs attempt to detect the number of colours a terminal is capable of
by checking the colors terminfo or Co termcap entry. However, this is not
reliable, and in any case is missing from the "screen" terminal description
used inside tmux.
There are two options (aside from using "screen-256color") to allow programs to
recognise they are running on a 256-colour terminal inside tmux:
- Manually force the application to use 256 colours always or if TERM is set to
screen. For vim, you can do this by overriding the t_Co option, see
http://vim.wikia.com/wiki/256_colors_in_vim.
- Creating a custom terminfo file that includes colors#256 in ~/.terminfo and
using it instead. These may be compiled with tic(1).
* How do I make Ctrl-PgUp and Ctrl-PgDn work in vim?
tmux supports passing through ctrl (and where supported by the client terminal,
alt and shift) modifiers to function keys using xterm(1)-style key sequences.
This may be enabled per window, or globally with the tmux command:
setw -g xterm-keys on
Because the TERM variable inside tmux must be set to "screen", vim will not
automatically detect these keys are available; however, the appropriate key
sequences can be overridden in .vimrc using the following:
if &term == "screen"
set t_kN=^[[6;*~
set t_kP=^[[5;*~
endif
And similarly for any other keys for which modifiers are desired.
Please note that the "xterm-keys" setting may affect other programs, in the
same way as running them in a standard xterm; for example most shells do not
expect to receive xterm(1)-style key sequences so this setting may prevent keys
such as ctrl-left and ctrl-right working correctly. tmux also passes through
the ctrl (bit 5 set, for example ^[[5~ to ^[[5^) modifier in non-xterm(1) mode;
it may be possible to configure vim to accept these, an example of how to do so
would be welcome.
vim users may also want to set the "ttyfast" option inside tmux.
* How do I make ctrl and shift arrow keys work in emacs?
The terminal-init-screen function in term/screen.el is called for new frames,
but it doesn't configure any function keys.
If the tmux xterm-keys option is on, it is enough to define the same keys as
xterm. Add the following to init.el or .emacs to do this:
(defadvice terminal-init-screen
;; The advice is named `tmux', and is run before `terminal-init-screen' runs.
(before tmux activate)
;; Docstring. This describes the advice and is made available inside emacs;
;; for example when doing C-h f terminal-init-screen RET
"Apply xterm keymap, allowing use of keys passed through tmux."
;; This is the elisp code that is run before `terminal-init-screen'.
(if (getenv "TMUX")
(let ((map (copy-keymap xterm-function-map)))
(set-keymap-parent map (keymap-parent input-decode-map))
(set-keymap-parent input-decode-map map))))
And ensure .tmux.conf contains "set -g xterm-keys on".
Alternatively, the screen.el file can be copied to the load path and
customized.
* Why doesn't elinks set the window title inside tmux?
There isn't a way to detect if a terminal supports setting the window title, so
elinks attempts to guess by looking at the environment. Rather than looking for
TERM=screen, it uses the STY variable to detect if it is running in screen;
tmux does not use this so the check fails. A workaround is to set STY before
running elinks.
The following shell function does this, and also clears the window title on
exit (elinks, for some strange reason, sets it to the value of TERM):
elinks() {
STY= `which elinks` $*
echo -ne \\033]0\;\\007;
}
* What is the proper way to escape characters with #(command)?
When using the #(command) construction to include the output from a command in
the status line, the command will be parsed twice. First, when it's read by the
configuration file or the command-prompt parser, and second when the status
line is being drawn and the command is passed to the shell. For example, to
echo the string "(test)" to the status line, either single or double quotes
could be used:
set -g status-right "#(echo \\\\(test\\\\))"
set -g status-right '#(echo \\\(test\\\))'
In both cases, the status-right option will be set to the string "#(echo
\\(test\\))" and the command executed will be "echo \(test\)".
* tmux uses too much CPU. What do I do?
Automatic window renaming may use a lot of CPU, particularly on slow computers:
if this is a problem, turn it off with "setw -g automatic-rename off". If this
doesn't fix it, please report the problem.
* I use PuTTY and my tmux window pane separators are all qqqqqqqqq's!
PuTTY is using a character set translation that doesn't support ACS line
drawing. With a Unicode font, try setting PuTTY to use a different translation
on the Window -> Translation configuration page. For example, change UTF-8 to
ISO-8859-1 or CP437. It may also be necessary to adjust the way PuTTY treats
line drawing characters in the lower part of the same configuration page.
* What is the best way to display the load average? Why no #L?
It isn't possible to get the load average portably in code and it is preferable
not to add portability goop. The following works on at least Linux, *BSD and OS
X:
uptime|awk '{split(substr($0, index($0, "load")), a, ":"); print a[2]}'
* How do I attach the same session to multiple clients but with a different
current window, like screen -x?
One or more of the windows can be linked into multiple sessions manually with
link-window, or a grouped session with all the windows can be created with
new-session -t.
* Ctrl and arrow keys doesn't work in putty! What do I do?
putty inverts the sense of the cursor key mode on ctrl, which is a bit hard for
tmux to detect properly. To get ctrl keys right, change the terminfo settings
so kUP5 (Ctrl-Up etc) are the adjusted versions, and disable smkx/rmkx so tmux
doesn't change the mode. For example with this line in .tmux.conf (assuming you
have TERM set to xterm):
set -g terminal-overrides "xterm*:kLFT5=\eOD:kRIT5=\eOC:kUP5=\eOA:kDN5=\eOB:smkx@:rmkx@"
Note that this will only work in tmux 1.2 and above.
* How can I blank the tmux window?
GNU screen has a feature whereby it will blank the screen after a period of
inactivity. To do the same thing in tmux, use the lock-command setting, for
example (with GNU bash):
set -g lock-command 'tput civis && read -s -n1'
This will remove the cursor and tell the shell to quit once a key has been
pressed. For zsh, use "read -s -k1".
In addition, it's possible to have both blanking and locking (for instance via
lock(1) or vlock(1)) by using the following:
bind x set lock-command '/usr/bin/vlock' \; lock-client \; set lock-command 'tput civis && read -s -n1'
* I don't see italics! Or less and vim show italics and reverse the wrong way round!
GNU screen does not support italics and the "screen" terminfo description uses
the italics escape sequence incorrectly.
As of tmux 2.1, if default-terminal is set to "screen" or matches "screen-*",
tmux will behave like screen and italics will be disabled.
To enable italics, create a new terminfo entry called "tmux" (some platforms
may already have this, you can check with "infocmp tmux"):
$ cat <<EOF|tic -x -
tmux|tmux terminal multiplexer,
ritm=\E[23m, rmso=\E[27m, sitm=\E[3m, smso=\E[7m, Ms@,
use=xterm+tmux, use=screen,
tmux-256color|tmux with 256 colors,
use=xterm+256setaf, use=tmux,
EOF
$
And tell tmux to use it in ~/.tmux.conf:
set -g default-terminal "tmux"
If using urxvt, make sure you have an italics capable font enabled. for
example, add to ~/.Xdefaults:
urxvt.italicFont: xft:Bitstream Vera Sans Mono:italic:autohint=true
* How can I make tmux use my terminal's scrollback buffer?
Normally, tmux enables the terminal's "alternate screen". Most terminals (such
as xterm) do not save scrollback for the alternate screen. You might prefer
tmux to use the normal screen, so it uses your terminal's scrollback
buffer. This way, you can access the scrollback buffer as usual, for example
using the mouse wheel - although there is no guarantee output inside tmux will
always (or ever) be added to the scrollback.
You can make tmux use the normal screen by telling it that your terminal does
not have an alternate screen. Put the following in ~/.tmux.conf:
set -ga terminal-overrides ',xterm*:smcup@:rmcup@'
Adjust if your $TERM does not start with xterm.
tmux will still emulate the alternate screen for applications run under tmux,
so you don't really lose anything with this setting. The only disadvantage is
that when you exit tmux, it will not restore whatever was there before you
started.
* How do I see the default configuration?
Show the default session options by starting a new tmux server with no
configuration file:
$ tmux -Lfoo -f/dev/null start\; show -g
Or the default window options:
$ tmux -Lfoo -f/dev/null start\; show -gw
* How do I copy a selection from tmux to the system's clipboard?
When running in xterm(1), tmux can automatically send copied text to the
clipboard. This is controlled by the set-clipboard option and also needs this
X resource to be set:
XTerm*disallowedWindowOps: 20,21,SetXprop
For rxvt-unicode (urxvt), there is an unofficial Perl extension here:
http://anti.teamidiot.de/static/nei/*/Code/urxvt/
Otherwise a key binding for copy mode using xclip (or xsel) works:
bind -temacs-copy C-y copy-pipe "xclip -i >/dev/null"
Or for inside and outside copy mode with the prefix key:
bind C-y run -b "tmux save-buffer - | xclip -i"
On OS X, reattach-to-usernamespace lets pbcopy/pbpaste work:
https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard
* Why do I see dots around a session when I attach to it?
tmux limits the size of the window to the smallest attached session. If
it didn't do this then it would be impossible to see the entire window.
The dots mark the size of the window tmux can display.
To avoid this, detach all other clients when attaching:
$ tmux attach -d
Or from inside tmux by detaching individual clients with C-b D or all
using:
C-b : attach -d

View File

@@ -2,65 +2,57 @@
# Obvious program stuff. # Obvious program stuff.
bin_PROGRAMS = tmux bin_PROGRAMS = tmux
CLEANFILES = tmux.1.mdoc tmux.1.man CLEANFILES = tmux.1.mdoc tmux.1.man cmd-parse.c
# Distribution tarball options. # Distribution tarball options.
EXTRA_DIST = \ EXTRA_DIST = \
CHANGES FAQ README TODO COPYING example_tmux.conf compat/*.[ch] \ CHANGES README README.ja COPYING example_tmux.conf compat/*.[ch] \
compat.h tmux.h osdep-*.c xmalloc.h mdoc2man.awk tmux.1 osdep-*.c mdoc2man.awk tmux.1
dist-hook:
make clean
grep "^#found_debug=" configure
# Preprocessor flags. # Preprocessor flags.
CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\"" AM_CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\""
# glibc as usual does things ass-backwards and hides useful things by default, # Additional object files.
# so everyone has to add this. LDADD = $(LIBOBJS)
if IS_GLIBC
CFLAGS += -D_GNU_SOURCE
endif
# Set flags for gcc. # Set flags for gcc.
if IS_GCC if IS_GCC
CFLAGS += -std=gnu99 -O2 AM_CFLAGS += -std=gnu99 -O2
if IS_DEBUG if IS_DEBUG
CFLAGS += -g AM_CFLAGS += -g
CFLAGS += -Wno-long-long -Wall -W -Wformat=2 AM_CFLAGS += -Wno-long-long -Wall -W -Wformat=2
CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations AM_CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
CPPFLAGS += -DDEBUG AM_CFLAGS += -Wno-unused-result
AM_CPPFLAGS += -DDEBUG
endif endif
if IS_COVERAGE AM_CPPFLAGS += -iquote.
CFLAGS += -g -O0 --coverage
LDFLAGS += --coverage
endif
if IS_PROFILE
CFLAGS += -g -O0 -pg
LDFLAGS += -pg
endif
CPPFLAGS += -iquote.
endif endif
# Set flags for Solaris. # Set flags for Solaris.
if IS_SUNOS if IS_SUNOS
if IS_GCC if IS_GCC
CPPFLAGS += -D_XPG6 -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS AM_CPPFLAGS += -D_XPG6
else else
CPPFLAGS += -D_XPG4_2 -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS AM_CPPFLAGS += -D_XPG4_2
endif endif
endif endif
# Set flags for Sun CC. # Set flags for Sun CC.
if IS_SUNCC if IS_SUNCC
CFLAGS += -erroff=E_EMPTY_DECLARATION AM_CFLAGS += -erroff=E_EMPTY_DECLARATION
endif endif
# Set _LINUX_SOURCE_COMPAT for AIX for malloc(0). # Set _LINUX_SOURCE_COMPAT for AIX for malloc(0).
if IS_AIX if IS_AIX
DEFS += -D_LINUX_SOURCE_COMPAT=1 AM_CPPFLAGS += -D_LINUX_SOURCE_COMPAT=1
endif
# Set flags for NetBSD.
if IS_NETBSD
AM_CPPFLAGS += -D_OPENBSD_SOURCE
endif endif
# List of sources. # List of sources.
@@ -74,18 +66,16 @@ dist_tmux_SOURCES = \
cmd-bind-key.c \ cmd-bind-key.c \
cmd-break-pane.c \ cmd-break-pane.c \
cmd-capture-pane.c \ cmd-capture-pane.c \
cmd-choose-buffer.c \
cmd-choose-client.c \
cmd-choose-tree.c \ cmd-choose-tree.c \
cmd-clear-history.c \
cmd-command-prompt.c \ cmd-command-prompt.c \
cmd-confirm-before.c \ cmd-confirm-before.c \
cmd-copy-mode.c \ cmd-copy-mode.c \
cmd-detach-client.c \ cmd-detach-client.c \
cmd-display-menu.c \
cmd-display-message.c \ cmd-display-message.c \
cmd-display-panes.c \ cmd-display-panes.c \
cmd-find.c \
cmd-find-window.c \ cmd-find-window.c \
cmd-find.c \
cmd-if-shell.c \ cmd-if-shell.c \
cmd-join-pane.c \ cmd-join-pane.c \
cmd-kill-pane.c \ cmd-kill-pane.c \
@@ -98,12 +88,12 @@ dist_tmux_SOURCES = \
cmd-list-panes.c \ cmd-list-panes.c \
cmd-list-sessions.c \ cmd-list-sessions.c \
cmd-list-windows.c \ cmd-list-windows.c \
cmd-list.c \
cmd-load-buffer.c \ cmd-load-buffer.c \
cmd-lock-server.c \ cmd-lock-server.c \
cmd-move-window.c \ cmd-move-window.c \
cmd-new-session.c \ cmd-new-session.c \
cmd-new-window.c \ cmd-new-window.c \
cmd-parse.y \
cmd-paste-buffer.c \ cmd-paste-buffer.c \
cmd-pipe-pane.c \ cmd-pipe-pane.c \
cmd-queue.c \ cmd-queue.c \
@@ -111,6 +101,7 @@ dist_tmux_SOURCES = \
cmd-rename-session.c \ cmd-rename-session.c \
cmd-rename-window.c \ cmd-rename-window.c \
cmd-resize-pane.c \ cmd-resize-pane.c \
cmd-resize-window.c \
cmd-respawn-pane.c \ cmd-respawn-pane.c \
cmd-respawn-window.c \ cmd-respawn-window.c \
cmd-rotate-window.c \ cmd-rotate-window.c \
@@ -122,14 +113,12 @@ dist_tmux_SOURCES = \
cmd-send-keys.c \ cmd-send-keys.c \
cmd-set-buffer.c \ cmd-set-buffer.c \
cmd-set-environment.c \ cmd-set-environment.c \
cmd-set-hook.c \
cmd-set-option.c \ cmd-set-option.c \
cmd-show-environment.c \ cmd-show-environment.c \
cmd-show-messages.c \ cmd-show-messages.c \
cmd-show-options.c \ cmd-show-options.c \
cmd-source-file.c \ cmd-source-file.c \
cmd-split-window.c \ cmd-split-window.c \
cmd-string.c \
cmd-swap-pane.c \ cmd-swap-pane.c \
cmd-swap-window.c \ cmd-swap-window.c \
cmd-switch-client.c \ cmd-switch-client.c \
@@ -137,13 +126,14 @@ dist_tmux_SOURCES = \
cmd-wait-for.c \ cmd-wait-for.c \
cmd.c \ cmd.c \
colour.c \ colour.c \
control.c \ compat.h \
control-notify.c \ control-notify.c \
control.c \
environ.c \ environ.c \
format.c \ format.c \
format-draw.c \
grid-view.c \ grid-view.c \
grid.c \ grid.c \
hooks.c \
input-keys.c \ input-keys.c \
input.c \ input.c \
job.c \ job.c \
@@ -153,13 +143,15 @@ dist_tmux_SOURCES = \
layout-set.c \ layout-set.c \
layout.c \ layout.c \
log.c \ log.c \
mode-key.c \ menu.c \
mode-tree.c \
names.c \ names.c \
notify.c \ notify.c \
options-table.c \ options-table.c \
options.c \ options.c \
paste.c \ paste.c \
proc.c \ proc.c \
regsub.c \
resize.c \ resize.c \
screen-redraw.c \ screen-redraw.c \
screen-write.c \ screen-write.c \
@@ -168,93 +160,37 @@ dist_tmux_SOURCES = \
server-fn.c \ server-fn.c \
server.c \ server.c \
session.c \ session.c \
signal.c \ spawn.c \
status.c \ status.c \
style.c \ style.c \
tmux.c \ tmux.c \
tmux.h \
tty-acs.c \ tty-acs.c \
tty-keys.c \ tty-keys.c \
tty-term.c \ tty-term.c \
tty.c \ tty.c \
utf8.c \ utf8.c \
window-choose.c \ window-buffer.c \
window-client.c \
window-clock.c \ window-clock.c \
window-copy.c \ window-copy.c \
window-tree.c \
window.c \ window.c \
xmalloc.c \ xmalloc.c \
xmalloc.h \
xterm-keys.c xterm-keys.c
nodist_tmux_SOURCES = osdep-@PLATFORM@.c nodist_tmux_SOURCES = osdep-@PLATFORM@.c
# Add compat file for forkpty.
if NEED_FORKPTY
nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c
endif
# Add compat file for utf8proc. # Add compat file for utf8proc.
if HAVE_UTF8PROC if HAVE_UTF8PROC
nodist_tmux_SOURCES += compat/utf8proc.c nodist_tmux_SOURCES += compat/utf8proc.c
endif endif
# Add compat for missing or broken functions.
if NO_FORKPTY
nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c
endif
if NO_IMSG
nodist_tmux_SOURCES += compat/imsg.c compat/imsg-buffer.c
endif
if NO_CLOSEFROM
nodist_tmux_SOURCES += compat/closefrom.c
endif
if NO_DAEMON
nodist_tmux_SOURCES += compat/daemon.c
endif
if NO_GETPROGNAME
nodist_tmux_SOURCES += compat/getprogname.c
endif
if NO_SETPROCTITLE
nodist_tmux_SOURCES += compat/setproctitle.c
endif
if NO_SETENV
nodist_tmux_SOURCES += compat/setenv.c
endif
if NO_STRLCAT
nodist_tmux_SOURCES += compat/strlcat.c
endif
if NO_STRLCPY
nodist_tmux_SOURCES += compat/strlcpy.c
endif
if NO_ASPRINTF
nodist_tmux_SOURCES += compat/asprintf.c
endif
if NO_FGETLN
nodist_tmux_SOURCES += compat/fgetln.c
endif
if NO_FPARSELN
nodist_tmux_SOURCES += compat/fparseln.c
endif
if NO_GETOPT
nodist_tmux_SOURCES += compat/getopt.c
endif
if NO_STRCASESTR
nodist_tmux_SOURCES += compat/strcasestr.c
endif
if NO_STRSEP
nodist_tmux_SOURCES += compat/strsep.c
endif
if NO_VIS
nodist_tmux_SOURCES += compat/vis.c compat/unvis.c
endif
if NO_STRTONUM
nodist_tmux_SOURCES += compat/strtonum.c
endif
if NO_B64_NTOP
nodist_tmux_SOURCES += compat/b64_ntop.c
endif
if NO_CFMAKERAW
nodist_tmux_SOURCES += compat/cfmakeraw.c
endif
if NO_OPENAT
nodist_tmux_SOURCES += compat/openat.c
endif
if NO_REALLOCARRAY
nodist_tmux_SOURCES += compat/reallocarray.c
endif
# Install tmux.1 in the right format. # Install tmux.1 in the right format.
install-exec-hook: install-exec-hook:
if test x@MANFORMAT@ = xmdoc; then \ if test x@MANFORMAT@ = xmdoc; then \
@@ -262,7 +198,7 @@ install-exec-hook:
>$(srcdir)/tmux.1.mdoc; \ >$(srcdir)/tmux.1.mdoc; \
else \ else \
sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1| \ sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1| \
$(AWK) -f$(srcdir)/mdoc2man.awk >$(srcdir)/tmux.1.man; \ $(AWK) -f $(srcdir)/mdoc2man.awk >$(srcdir)/tmux.1.man; \
fi fi
$(mkdir_p) $(DESTDIR)$(mandir)/man1 $(mkdir_p) $(DESTDIR)$(mandir)/man1
$(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \ $(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \

94
README
View File

@@ -1,69 +1,75 @@
Welcome to tmux! Welcome to tmux!
tmux is a "terminal multiplexer", it enables a number of terminals (or windows) tmux is a terminal multiplexer: it enables a number of terminals to be created,
to be accessed and controlled from a single terminal. tmux is intended to be a accessed, and controlled from a single screen. tmux may be detached from a
simple, modern, BSD-licensed alternative to programs such as GNU screen. screen and continue running in the background, then later reattached.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris. This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
tmux depends on libevent 2.x. Download it from: * Dependencies
http://libevent.org tmux depends on libevent 2.x, available from:
To build tmux from a release tarball, do: https://github.com/libevent/libevent/releases/latest
It also depends on ncurses, available from:
https://invisible-mirror.net/archives/ncurses/
* Installation
To build and install tmux from a release tarball, use:
$ ./configure && make $ ./configure && make
$ sudo make install $ sudo make install
By default, tmux will use the utempter library to update utmp(5), if it is tmux can use the utempter library to update utmp(5), if it is installed - run
installed. Run configure with --disable-utempter to disable this. configure with --enable-utempter to enable this.
To get and build the latest from version control: To get and build the latest from version control - note that this requires
autoconf, automake and pkg-config:
$ git clone https://github.com/tmux/tmux.git $ git clone https://github.com/tmux/tmux.git
$ cd tmux $ cd tmux
$ sh autogen.sh $ sh autogen.sh
$ ./configure && make $ ./configure && make
For more information see http://git-scm.com. Patches should be sent by email to * Contributing
the mailing list at tmux-users@googlegroups.com.
For documentation on using tmux, see the tmux.1 manpage. It can be viewed from
the source tree with:
$ nroff -mdoc tmux.1|less
Some common questions are answered in the FAQ file, a rough todo list is in the
TODO file and an example configuration in example_tmux.conf.
A vim(1) syntax file is available at:
https://github.com/keith/tmux.vim
https://raw.githubusercontent.com/keith/tmux.vim/master/syntax/tmux.vim
And a bash(1) completion file at:
https://github.com/imomaliev/tmux-bash-completion
For debugging, running tmux with -v or -vv will generate server and client log
files in the current directory.
tmux mailing lists are available. For general discussion and bug reports:
https://groups.google.com/forum/#!forum/tmux-users
And for Git commit emails:
https://groups.google.com/forum/#!forum/tmux-git
Subscribe by sending an email to <tmux-users+subscribe@googlegroups.com>.
Bug reports, feature suggestions and especially code contributions are most Bug reports, feature suggestions and especially code contributions are most
welcome. Please send by email to: welcome. Please send by email to:
tmux-users@googlegroups.com tmux-users@googlegroups.com
This file and the CHANGES, FAQ, SYNCING and TODO files are licensed under the Or open a GitHub issue or pull request.
ISC license. All other files have a license and copyright notice at their start.
-- Nicholas Marriott <nicholas.marriott@gmail.com> * Documentation
For documentation on using tmux, see the tmux.1 manpage. View it from the
source tree with:
$ nroff -mdoc tmux.1|less
A small example configuration is in example_tmux.conf.
A bash(1) completion file is at:
https://github.com/imomaliev/tmux-bash-completion
For debugging, run tmux with -v and -vv to generate server and client log files
in the current directory.
* Support
The tmux mailing list for general discussion and bug reports is:
https://groups.google.com/forum/#!forum/tmux-users
Subscribe by sending an email to:
tmux-users+subscribe@googlegroups.com
* License
This file and the CHANGES files are licensed under the ISC license. All other
files have a license and copyright notice at their start.

62
README.ja Normal file
View File

@@ -0,0 +1,62 @@
tmuxへようこそ!
tmuxはターミナルマルチプレクサーです。複数のターミナルを一つのスクリーン内に作成し、操作することができます。
バックグラウンドで処理を実行中に一度スクリーンから離れて後から復帰することも可能です。
OpenBSD、FreeBSD、NetBSD、Linux、OS X、Solarisで実行できます。
tmuxはlibevent 2.x.に依存します。 下記からダウンロードしてください。
http://libevent.org
また、ncursesも必要です。こちらからどうぞ。
http://invisible-island.net/ncurses/
tarballでのtmuxのビルドとインストール方法。
$ ./configure && make
$ sudo make install
tmuxはutmp(5)をアップデートするためにutempterを使うことができます。もしインストール済みであればオプション「--enable-utempter」をつけて実行してください。
リポジトリから最新バージョンを手に入れるためには下記を実行。
$ git clone https://github.com/tmux/tmux.git
$ cd tmux
$ sh autogen.sh
$ ./configure && make
(ビルドのためにはlibevent、ncurses libraries、headersに加えて、C compiler、make、autoconf、automake、pkg-configが必要です。)
詳しい情報はhttp://git-scm.comをご覧ください。修正はメール<tmux-users@googlegroups.com>宛、もしくはhttps://github.com/tmux/tmux/issuesにて受け付けています。
tmuxのドキュメントについてはtmux.1マニュアルをご覧ください。こちらのコマンドで参照可能です。
$ nroff -mdoc tmux.1|less
サンプル設定は本リポジトリのexample_tmux.confに
また、bash-completionファイルは下記にあります。
https://github.com/imomaliev/tmux-bash-completion
「-v」や「-vv」を指定することでデバッグモードでの起動が可能です。カレントディレクトリにサーバーやクライアントのログファイルが生成されます。
議論やバグレポート用のメーリングリストにはこちらから参加可能です。
https://groups.google.com/forum/#!forum/tmux-users
gitコミットについての連絡先
https://groups.google.com/forum/#!forum/tmux-git
購読は<tmux-users+subscribe@googlegroups.com>までメールをお願いします。
バグレポートや機能追加(特にコードへの貢献)は大歓迎です。こちらにご連絡ください。
tmux-users@googlegroups.com
本ファイル、CHANGES、 FAQ、SYNCINGそしてTODOはISC licenseで保護されています。
その他のファイルのライセンスや著作権については、ファイルの上部に明記されています。
-- Nicholas Marriott <nicholas.marriott@gmail.com>

19
SYNCING
View File

@@ -140,15 +140,13 @@ to compat/ as and when appropriate.
Release tmux for next version Release tmux for next version
============================= =============================
1. Comment the "found_debug=yes" line in configure.ac, since releases 1. Update and commit README and CHANGES. The former should be checked for
don't have debugging enabled, otherwise make(1) aborts when
preparing the distribution.
2. Update and commit README and CHANGES. The former should be checked for
anything outdated and updated with a list of things that might break anything outdated and updated with a list of things that might break
upgrades and the latter should mention all the major changes since upgrades and the latter should mention all the major changes since
the last version. the last version.
2. Make sure configure.ac has the new version number.
3. Tag with: 3. Tag with:
% git tag -a 2.X % git tag -a 2.X
@@ -157,7 +155,7 @@ Release tmux for next version
Push the tag out with: Push the tag out with:
% git push 2.X % git push --tags
4. Build the tarball with 'make dist'. 4. Build the tarball with 'make dist'.
@@ -168,9 +166,8 @@ Release tmux for next version
Click the "Add release notes", upload the tarball and add a link in the Click the "Add release notes", upload the tarball and add a link in the
description field to the CHANGES file. description field to the CHANGES file.
7. Clone the tmux.github.io repository, and change the RELEASE version in 6. Clone the tmux.github.io repository, and change the RELEASE version in the
the Makefile. Commit it, and run 'make' to replace %%VERSION%%. Push Makefile. Commit it, and run 'make' to replace %%RELEASE%%. Push the
the result out. result out.
8. Bump version in tmux/tmux.git configure.ac and uncomment "found_debug=yes" to 7. Change version back to master in configure.ac.
create a debug build by default.

143
TODO
View File

@@ -1,143 +0,0 @@
- command bits and pieces:
* allow multiple targets: fnmatch for -t/-c, for example detach all
clients with -t*
* add -c for new-session like new-window
* ' and " should be parsed the same (eg "\e" vs '\e') in config
and command prompt
* last-pane across sessions
* list-keys should quote output so that bindings can just be used in
config file as-is
* resize-pane -p to match split-window -p
- make command sequences more usable
* don't require space after ;
* options for error handling: && and ||?
- options bits and pieces:
* set-remain-on-exit is a complete hack
* way to set socket path from config file
- format improvements:
* option to quote format (#{q:session_name})
* formats need conditions for >0 (for #P)
* some way to pad # stuff with spaces
* formats to show if a window is linked into multiple sessions, into
multiple attached sessions, and is the active window in multiple
attached sessions?
- choose mode improvements:
* choose-pane command (augment choose-tree to do this?)
* choose-mode and copy-mode are very similar, make choose-mode a subset?
* flag to choose-* for sort order
* choose mode would be better per client than per window?
* two choices (first one then second, for swap-pane and join-pane)
* choose modes should ditch the key bindings and just have fixed keys, and
be more customized to their purpose (d to delete a buffer for choose-buffer,
a preview of buffer contents, etc)
- improve monitor-*:
* straighten out rules for multiple clients
* think about what happens across sessions
* monitor changes within a region
* perhaps monitor /all/ panes in the window not just one
- improve mouse support:
* bind commands to mouse in different areas?
* commands executed when clicking on a pattern (URL)
- warts on current naming:
* display-time but message-fg/bg/attr
* list-* vs show-*
* split-window -> split-pane?
- better UTF-8 support:
* message display
* prompt input
* searching in copy mode
- copy/paste improvements:
* incremental searching
* paste w/o trailing whitespace
* command to toggle selection not to move it in copy-mode
* regex searching
* copy-pipe should have -x as well
* copy mode key bindings should just be a standard key table, using
something like "copy-mode start-selection"; it could use
command-prompt for search, goto, etc:
bind -Temacs command-prompt -p'Search Up: ' 'copy-mode search-up %%'
it'd need a separate lookup, because modes are per-pane, perhaps a
table() cb to give the table name ("vi" or "emacs"). anything in the
table fires the command, anything not in the table is injected as a
key
* searching in copy mode should unwrap lines, so if you search for "foobar"
then it should be found even if it is now "foo\nbar" (if the WRAP flag
is set on the line)
* capture-pane option to preserve spaces but not join lines
- layout stuff
* way to tag a layout as a number/name
* maybe keep last layout + size around and if size reverts just put it
back
* revamp layouts: they are too complicated, should be more closely
integrated, should support hints, layout sets should just be a
special case of custom layouts, and we should support panes that are
not attached to a cell at all. this could be the time to introduce
panelink to replace layout_cell
* way to set hints/limits about pane size for resizing
* panning over window (window larger than visible)
* a mode where one application can cross two panes (ie x|y, width =
COLUMNS/2 but height = ROWS * 2)
* general key to space cells out evenly (horiz or vert) within their
parent cell (could replace even-vert/even-horiz layouts)
* separate active panes for different clients
- terminfo bits
* use a better termcap internally instead of screen, perhaps xterm
* use screen-256color when started on 256 colour terminal?
- code cleanup
* instead of separate window and session options, just one master
options list with each option having a type (window or session), then
options on window, on session, and global. for window options we look
window->session->global, and for session we look session->global
* the way pane, window, session destroy is handled is too complicated
and the distinction between session.c, window.c and server-fn.c
functions is not clear. could we just have kill_pane(),
kill_window(), unlink_window(), kill_session() that fix up all data
structures (flagging sessions as dead) and return a value to say
whether clients need to be checked for dead sessions? sort of like
session_detach now but more so. or some other scheme to make it
simpler and clearer? also would be nice to remove/rename server-fn.c
* more readable way to work out the various things commands need to
know about the client, notably:
- is this the config file? (cmdq->c == NULL)
- is this a command client? (cmdq->c != NULL &&
cmdq->c->session == NULL)
- is this a control client?
- can i do stdin or stdout to this client?
or even guarantee that cmdq->c != NULL and provide a better way to
tell when in the config file - then we use cmdq->c if we need a
client w/o a session else cmd_current_client
* we do more work than we should if a single read() contains operations
that cancel each other out: for example, writing twice to the same
cell, or writing and then clearing a line; it would be nice to
optimize these. would it mean processing the entire read() data first
then applying changes? or an initial optimization step? or something
else?
- miscellaneous
* way to keep a job running just read its last line of output for #()
* link panes into multiple windows
* live update: server started with -U connects to server, requests
sessions and windows, receives file descriptors
* there are inconsistencies in what we get from old shell and what
comes from config for new sessions and windows. likewise, panes and
jobs and run-shell and lock command all start with slightly different
environments
* multiline status line? separate command prompt and status line?
* customizable command aliases
* automatic pane logging
* BCE? We are halfway there (output side is done for pane backgrounds),
just need to change how screen/grid handles erase

305
alerts.c
View File

@@ -19,88 +19,84 @@
#include <sys/types.h> #include <sys/types.h>
#include <event.h> #include <event.h>
#include <stdlib.h>
#include "tmux.h" #include "tmux.h"
int alerts_fired; static int alerts_fired;
void alerts_timer(int, short, void *); static void alerts_timer(int, short, void *);
int alerts_enabled(struct window *, int); static int alerts_enabled(struct window *, int);
void alerts_callback(int, short, void *); static void alerts_callback(int, short, void *);
void alerts_reset(struct window *); static void alerts_reset(struct window *);
void alerts_run_hook(struct session *, struct winlink *, int); static int alerts_action_applies(struct winlink *, const char *);
int alerts_check_all(struct session *, struct winlink *); static int alerts_check_all(struct window *);
int alerts_check_bell(struct session *, struct winlink *); static int alerts_check_bell(struct window *);
int alerts_check_activity(struct session *, struct winlink *); static int alerts_check_activity(struct window *);
int alerts_check_silence(struct session *, struct winlink *); static int alerts_check_silence(struct window *);
void alerts_ring_bell(struct session *); static void alerts_set_message(struct winlink *, const char *,
const char *);
void static TAILQ_HEAD(, window) alerts_list = TAILQ_HEAD_INITIALIZER(alerts_list);
static void
alerts_timer(__unused int fd, __unused short events, void *arg) alerts_timer(__unused int fd, __unused short events, void *arg)
{ {
struct window *w = arg; struct window *w = arg;
log_debug("@%u alerts timer expired", w->id); log_debug("@%u alerts timer expired", w->id);
alerts_reset(w);
alerts_queue(w, WINDOW_SILENCE); alerts_queue(w, WINDOW_SILENCE);
} }
void static void
alerts_callback(__unused int fd, __unused short events, __unused void *arg) alerts_callback(__unused int fd, __unused short events, __unused void *arg)
{ {
struct window *w; struct window *w, *w1;
struct session *s; int alerts;
struct winlink *wl;
int flags, alerts;
RB_FOREACH(w, windows, &windows) { TAILQ_FOREACH_SAFE(w, &alerts_list, alerts_entry, w1) {
RB_FOREACH(s, sessions, &sessions) { alerts = alerts_check_all(w);
RB_FOREACH(wl, winlinks, &s->windows) { log_debug("@%u alerts check, alerts %#x", w->id, alerts);
if (wl->window != w)
continue;
flags = w->flags;
alerts = alerts_check_all(s, wl); w->alerts_queued = 0;
TAILQ_REMOVE(&alerts_list, w, alerts_entry);
log_debug("%s:%d @%u alerts check, alerts %#x, " w->flags &= ~WINDOW_ALERTFLAGS;
"flags %#x", s->name, wl->idx, w->id, window_remove_ref(w, __func__);
alerts, flags);
}
}
} }
alerts_fired = 0; alerts_fired = 0;
} }
void static int
alerts_run_hook(struct session *s, struct winlink *wl, int flags) alerts_action_applies(struct winlink *wl, const char *name)
{ {
struct cmd_find_state fs; int action;
if (cmd_find_from_winlink(&fs, s, wl) != 0) /*
return; * {bell,activity,silence}-action determines when to alert: none means
* nothing happens, current means only do something for the current
* window and other means only for windows other than the current.
*/
if (flags & WINDOW_BELL) action = options_get_number(wl->session->options, name);
hooks_run(s->hooks, NULL, &fs, "alert-bell"); if (action == ALERT_ANY)
if (flags & WINDOW_SILENCE) return (1);
hooks_run(s->hooks, NULL, &fs, "alert-silence"); if (action == ALERT_CURRENT)
if (flags & WINDOW_ACTIVITY) return (wl == wl->session->curw);
hooks_run(s->hooks, NULL, &fs, "alert-activity"); if (action == ALERT_OTHER)
return (wl != wl->session->curw);
return (0);
} }
int static int
alerts_check_all(struct session *s, struct winlink *wl) alerts_check_all(struct window *w)
{ {
int alerts; int alerts;
alerts = alerts_check_bell(s, wl); alerts = alerts_check_bell(w);
alerts |= alerts_check_activity(s, wl); alerts |= alerts_check_activity(w);
alerts |= alerts_check_silence(s, wl); alerts |= alerts_check_silence(w);
if (alerts != 0) {
alerts_run_hook(s, wl, alerts);
server_status_session(s);
}
return (alerts); return (alerts);
} }
@@ -110,14 +106,16 @@ alerts_check_session(struct session *s)
struct winlink *wl; struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows) RB_FOREACH(wl, winlinks, &s->windows)
alerts_check_all(s, wl); alerts_check_all(wl->window);
} }
int static int
alerts_enabled(struct window *w, int flags) alerts_enabled(struct window *w, int flags)
{ {
if (flags & WINDOW_BELL) if (flags & WINDOW_BELL) {
return (1); if (options_get_number(w->options, "monitor-bell"))
return (1);
}
if (flags & WINDOW_ACTIVITY) { if (flags & WINDOW_ACTIVITY) {
if (options_get_number(w->options, "monitor-activity")) if (options_get_number(w->options, "monitor-activity"))
return (1); return (1);
@@ -138,11 +136,14 @@ alerts_reset_all(void)
alerts_reset(w); alerts_reset(w);
} }
void static void
alerts_reset(struct window *w) alerts_reset(struct window *w)
{ {
struct timeval tv; struct timeval tv;
if (!event_initialized(&w->alerts_timer))
evtimer_set(&w->alerts_timer, alerts_timer, w);
w->flags &= ~WINDOW_SILENCE; w->flags &= ~WINDOW_SILENCE;
event_del(&w->alerts_timer); event_del(&w->alerts_timer);
@@ -157,138 +158,166 @@ alerts_reset(struct window *w)
void void
alerts_queue(struct window *w, int flags) alerts_queue(struct window *w, int flags)
{ {
if (w->flags & WINDOW_ACTIVITY) alerts_reset(w);
alerts_reset(w);
if (!event_initialized(&w->alerts_timer))
evtimer_set(&w->alerts_timer, alerts_timer, w);
if ((w->flags & flags) != flags) { if ((w->flags & flags) != flags) {
w->flags |= flags; w->flags |= flags;
log_debug("@%u alerts flags added %#x", w->id, flags); log_debug("@%u alerts flags added %#x", w->id, flags);
} }
if (!alerts_fired && alerts_enabled(w, flags)) { if (alerts_enabled(w, flags)) {
log_debug("alerts check queued (by @%u)", w->id); if (!w->alerts_queued) {
event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL); w->alerts_queued = 1;
alerts_fired = 1; TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
window_add_ref(w, __func__);
}
if (!alerts_fired) {
log_debug("alerts check queued (by @%u)", w->id);
event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
alerts_fired = 1;
}
} }
} }
int static int
alerts_check_bell(struct session *s, struct winlink *wl) alerts_check_bell(struct window *w)
{ {
struct client *c; struct winlink *wl;
struct window *w = wl->window; struct session *s;
int action, visual;
if (!(w->flags & WINDOW_BELL)) if (~w->flags & WINDOW_BELL)
return (0); return (0);
if (s->curw != wl) { if (!options_get_number(w->options, "monitor-bell"))
wl->flags |= WINLINK_BELL;
w->flags &= ~WINDOW_BELL;
}
if (s->curw->window == w)
w->flags &= ~WINDOW_BELL;
action = options_get_number(s->options, "bell-action");
if (action == BELL_NONE)
return (0); return (0);
visual = options_get_number(s->options, "visual-bell"); TAILQ_FOREACH(wl, &w->winlinks, wentry)
TAILQ_FOREACH(c, &clients, entry) { wl->session->flags &= ~SESSION_ALERTED;
if (c->session != s || c->flags & CLIENT_CONTROL)
continue; TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (!visual) { /*
if ((action == BELL_CURRENT && * Bells are allowed even if there is an existing bell (so do
c->session->curw->window == w) || * not check WINLINK_BELL).
(action == BELL_OTHER && */
c->session->curw->window != w) || s = wl->session;
action == BELL_ANY) if (s->curw != wl) {
tty_putcode(&c->tty, TTYC_BEL); wl->flags |= WINLINK_BELL;
continue; server_status_session(s);
} }
if (action == BELL_CURRENT && c->session->curw->window == w) if (!alerts_action_applies(wl, "bell-action"))
status_message_set(c, "Bell in current window"); continue;
else if (action == BELL_ANY || (action == BELL_OTHER && notify_winlink("alert-bell", wl);
c->session->curw->window != w))
status_message_set(c, "Bell in window %d", wl->idx); if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
alerts_set_message(wl, "Bell", "visual-bell");
} }
return (WINDOW_BELL); return (WINDOW_BELL);
} }
int static int
alerts_check_activity(struct session *s, struct winlink *wl) alerts_check_activity(struct window *w)
{ {
struct client *c; struct winlink *wl;
struct window *w = wl->window; struct session *s;
if (s->curw->window == w) if (~w->flags & WINDOW_ACTIVITY)
w->flags &= ~WINDOW_ACTIVITY;
if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY)
return (0); return (0);
if (s->curw == wl)
return (0);
if (!options_get_number(w->options, "monitor-activity")) if (!options_get_number(w->options, "monitor-activity"))
return (0); return (0);
if (options_get_number(s->options, "bell-on-alert")) TAILQ_FOREACH(wl, &w->winlinks, wentry)
alerts_ring_bell(s); wl->session->flags &= ~SESSION_ALERTED;
wl->flags |= WINLINK_ACTIVITY;
if (options_get_number(s->options, "visual-activity")) { TAILQ_FOREACH(wl, &w->winlinks, wentry) {
TAILQ_FOREACH(c, &clients, entry) { if (wl->flags & WINLINK_ACTIVITY)
if (c->session != s) continue;
continue; s = wl->session;
status_message_set(c, "Activity in window %d", wl->idx); if (s->curw != wl) {
wl->flags |= WINLINK_ACTIVITY;
server_status_session(s);
} }
if (!alerts_action_applies(wl, "activity-action"))
continue;
notify_winlink("alert-activity", wl);
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
alerts_set_message(wl, "Activity", "visual-activity");
} }
return (WINDOW_ACTIVITY); return (WINDOW_ACTIVITY);
} }
int static int
alerts_check_silence(struct session *s, struct winlink *wl) alerts_check_silence(struct window *w)
{ {
struct client *c; struct winlink *wl;
struct window *w = wl->window; struct session *s;
if (s->curw->window == w) if (~w->flags & WINDOW_SILENCE)
w->flags &= ~WINDOW_SILENCE;
if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE)
return (0); return (0);
if (s->curw == wl)
return (0);
if (options_get_number(w->options, "monitor-silence") == 0) if (options_get_number(w->options, "monitor-silence") == 0)
return (0); return (0);
if (options_get_number(s->options, "bell-on-alert")) TAILQ_FOREACH(wl, &w->winlinks, wentry)
alerts_ring_bell(s); wl->session->flags &= ~SESSION_ALERTED;
wl->flags |= WINLINK_SILENCE;
if (options_get_number(s->options, "visual-silence")) { TAILQ_FOREACH(wl, &w->winlinks, wentry) {
TAILQ_FOREACH(c, &clients, entry) { if (wl->flags & WINLINK_SILENCE)
if (c->session != s) continue;
continue; s = wl->session;
status_message_set(c, "Silence in window %d", wl->idx); if (s->curw != wl) {
wl->flags |= WINLINK_SILENCE;
server_status_session(s);
} }
if (!alerts_action_applies(wl, "silence-action"))
continue;
notify_winlink("alert-silence", wl);
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
alerts_set_message(wl, "Silence", "visual-silence");
} }
return (WINDOW_SILENCE); return (WINDOW_SILENCE);
} }
void static void
alerts_ring_bell(struct session *s) alerts_set_message(struct winlink *wl, const char *type, const char *option)
{ {
struct client *c; struct client *c;
int visual;
/*
* We have found an alert (bell, activity or silence), so we need to
* pass it on to the user. For each client attached to this session,
* decide whether a bell, message or both is needed.
*
* If visual-{bell,activity,silence} is on, then a message is
* substituted for a bell; if it is off, a bell is sent as normal; both
* mean both a bell and message is sent.
*/
visual = options_get_number(wl->session->options, option);
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
if (c->session == s && !(c->flags & CLIENT_CONTROL)) if (c->session != wl->session || c->flags & CLIENT_CONTROL)
continue;
if (visual == VISUAL_OFF || visual == VISUAL_BOTH)
tty_putcode(&c->tty, TTYC_BEL); tty_putcode(&c->tty, TTYC_BEL);
if (visual == VISUAL_OFF)
continue;
if (c->session->curw == wl)
status_message_set(c, "%s in current window", type);
else
status_message_set(c, "%s in window %d", type, wl->idx);
} }
} }

View File

@@ -28,49 +28,33 @@
* Manipulate command arguments. * Manipulate command arguments.
*/ */
struct args_value {
char *value;
TAILQ_ENTRY(args_value) entry;
};
TAILQ_HEAD(args_values, args_value);
struct args_entry { struct args_entry {
u_char flag; u_char flag;
char *value; struct args_values values;
u_int count;
RB_ENTRY(args_entry) entry; RB_ENTRY(args_entry) entry;
}; };
struct args_entry *args_find(struct args *, u_char); static struct args_entry *args_find(struct args *, u_char);
RB_GENERATE(args_tree, args_entry, entry, args_cmp); static int args_cmp(struct args_entry *, struct args_entry *);
RB_GENERATE_STATIC(args_tree, args_entry, entry, args_cmp);
/* Arguments tree comparison function. */ /* Arguments tree comparison function. */
int static int
args_cmp(struct args_entry *a1, struct args_entry *a2) args_cmp(struct args_entry *a1, struct args_entry *a2)
{ {
return (a1->flag - a2->flag); return (a1->flag - a2->flag);
} }
/* Create an arguments set with no flags. */
struct args *
args_create(int argc, ...)
{
struct args *args;
va_list ap;
int i;
args = xcalloc(1, sizeof *args);
args->argc = argc;
if (argc == 0)
args->argv = NULL;
else
args->argv = xcalloc(argc, sizeof *args->argv);
va_start(ap, argc);
for (i = 0; i < argc; i++)
args->argv[i] = xstrdup(va_arg(ap, char *));
va_end(ap);
return (args);
}
/* Find a flag in the arguments tree. */ /* Find a flag in the arguments tree. */
struct args_entry * static struct args_entry *
args_find(struct args *args, u_char ch) args_find(struct args *args, u_char ch)
{ {
struct args_entry entry; struct args_entry entry;
@@ -115,12 +99,18 @@ args_free(struct args *args)
{ {
struct args_entry *entry; struct args_entry *entry;
struct args_entry *entry1; struct args_entry *entry1;
struct args_value *value;
struct args_value *value1;
cmd_free_argv(args->argc, args->argv); cmd_free_argv(args->argc, args->argv);
RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) { RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
RB_REMOVE(args_tree, &args->tree, entry); RB_REMOVE(args_tree, &args->tree, entry);
free(entry->value); TAILQ_FOREACH_SAFE(value, &entry->values, entry, value1) {
TAILQ_REMOVE(&entry->values, value, entry);
free(value->value);
free(value);
}
free(entry); free(entry);
} }
@@ -146,6 +136,37 @@ args_print_add(char **buf, size_t *len, const char *fmt, ...)
free(s); free(s);
} }
/* Add value to string. */
static void
args_print_add_value(char **buf, size_t *len, struct args_entry *entry,
struct args_value *value)
{
char *escaped;
if (**buf != '\0')
args_print_add(buf, len, " -%c ", entry->flag);
else
args_print_add(buf, len, "-%c ", entry->flag);
escaped = args_escape(value->value);
args_print_add(buf, len, "%s", escaped);
free(escaped);
}
/* Add argument to string. */
static void
args_print_add_argument(char **buf, size_t *len, const char *argument)
{
char *escaped;
if (**buf != '\0')
args_print_add(buf, len, " ");
escaped = args_escape(argument);
args_print_add(buf, len, "%s", escaped);
free(escaped);
}
/* Print a set of arguments. */ /* Print a set of arguments. */
char * char *
args_print(struct args *args) args_print(struct args *args)
@@ -153,74 +174,108 @@ args_print(struct args *args)
size_t len; size_t len;
char *buf; char *buf;
int i; int i;
u_int j;
struct args_entry *entry; struct args_entry *entry;
struct args_value *value;
len = 1; len = 1;
buf = xcalloc(1, len); buf = xcalloc(1, len);
/* Process the flags first. */ /* Process the flags first. */
RB_FOREACH(entry, args_tree, &args->tree) { RB_FOREACH(entry, args_tree, &args->tree) {
if (entry->value != NULL) if (!TAILQ_EMPTY(&entry->values))
continue; continue;
if (*buf == '\0') if (*buf == '\0')
args_print_add(&buf, &len, "-"); args_print_add(&buf, &len, "-");
args_print_add(&buf, &len, "%c", entry->flag); for (j = 0; j < entry->count; j++)
args_print_add(&buf, &len, "%c", entry->flag);
} }
/* Then the flags with arguments. */ /* Then the flags with arguments. */
RB_FOREACH(entry, args_tree, &args->tree) { RB_FOREACH(entry, args_tree, &args->tree) {
if (entry->value == NULL) TAILQ_FOREACH(value, &entry->values, entry)
continue; args_print_add_value(&buf, &len, entry, value);
if (*buf != '\0')
args_print_add(&buf, &len, " -%c ", entry->flag);
else
args_print_add(&buf, &len, "-%c ", entry->flag);
if (strchr(entry->value, ' ') != NULL)
args_print_add(&buf, &len, "\"%s\"", entry->value);
else
args_print_add(&buf, &len, "%s", entry->value);
} }
/* And finally the argument vector. */ /* And finally the argument vector. */
for (i = 0; i < args->argc; i++) { for (i = 0; i < args->argc; i++)
if (*buf != '\0') args_print_add_argument(&buf, &len, args->argv[i]);
args_print_add(&buf, &len, " ");
if (strchr(args->argv[i], ' ') != NULL)
args_print_add(&buf, &len, "\"%s\"", args->argv[i]);
else
args_print_add(&buf, &len, "%s", args->argv[i]);
}
return (buf); return (buf);
} }
/* Escape an argument. */
char *
args_escape(const char *s)
{
static const char quoted[] = " #\"';${}";
char *escaped, *result;
int flags;
if (*s == '\0')
return (xstrdup(s));
if (s[0] != ' ' &&
(strchr(quoted, s[0]) != NULL || s[0] == '~') &&
s[1] == '\0') {
xasprintf(&escaped, "\\%c", s[0]);
return (escaped);
}
flags = VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL;
if (s[strcspn(s, quoted)] != '\0')
flags |= VIS_DQ;
utf8_stravis(&escaped, s, flags);
if (flags & VIS_DQ) {
if (*escaped == '~')
xasprintf(&result, "\"\\%s\"", escaped);
else
xasprintf(&result, "\"%s\"", escaped);
} else {
if (*escaped == '~')
xasprintf(&result, "\\%s", escaped);
else
result = xstrdup(escaped);
}
free(escaped);
return (result);
}
/* Return if an argument is present. */ /* Return if an argument is present. */
int int
args_has(struct args *args, u_char ch) args_has(struct args *args, u_char ch)
{ {
return (args_find(args, ch) == NULL ? 0 : 1); struct args_entry *entry;
entry = args_find(args, ch);
if (entry == NULL)
return (0);
return (entry->count);
} }
/* Set argument value in the arguments tree. */ /* Set argument value in the arguments tree. */
void void
args_set(struct args *args, u_char ch, const char *value) args_set(struct args *args, u_char ch, const char *s)
{ {
struct args_entry *entry; struct args_entry *entry;
struct args_value *value;
/* Replace existing argument. */ entry = args_find(args, ch);
if ((entry = args_find(args, ch)) != NULL) { if (entry == NULL) {
free(entry->value);
entry->value = NULL;
} else {
entry = xcalloc(1, sizeof *entry); entry = xcalloc(1, sizeof *entry);
entry->flag = ch; entry->flag = ch;
entry->count = 1;
TAILQ_INIT(&entry->values);
RB_INSERT(args_tree, &args->tree, entry); RB_INSERT(args_tree, &args->tree, entry);
} } else
entry->count++;
if (value != NULL) if (s != NULL) {
entry->value = xstrdup(value); value = xcalloc(1, sizeof *value);
value->value = xstrdup(s);
TAILQ_INSERT_TAIL(&entry->values, value, entry);
}
} }
/* Get argument value. Will be NULL if it isn't present. */ /* Get argument value. Will be NULL if it isn't present. */
@@ -231,7 +286,34 @@ args_get(struct args *args, u_char ch)
if ((entry = args_find(args, ch)) == NULL) if ((entry = args_find(args, ch)) == NULL)
return (NULL); return (NULL);
return (entry->value); return (TAILQ_LAST(&entry->values, args_values)->value);
}
/* Get first value in argument. */
const char *
args_first_value(struct args *args, u_char ch, struct args_value **value)
{
struct args_entry *entry;
if ((entry = args_find(args, ch)) == NULL)
return (NULL);
*value = TAILQ_FIRST(&entry->values);
if (*value == NULL)
return (NULL);
return ((*value)->value);
}
/* Get next value in argument. */
const char *
args_next_value(struct args_value **value)
{
if (*value == NULL)
return (NULL);
*value = TAILQ_NEXT(*value, entry);
if (*value == NULL)
return (NULL);
return ((*value)->value);
} }
/* Convert an argument value to a number. */ /* Convert an argument value to a number. */
@@ -242,13 +324,15 @@ args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
const char *errstr; const char *errstr;
long long ll; long long ll;
struct args_entry *entry; struct args_entry *entry;
struct args_value *value;
if ((entry = args_find(args, ch)) == NULL) { if ((entry = args_find(args, ch)) == NULL) {
*cause = xstrdup("missing"); *cause = xstrdup("missing");
return (0); return (0);
} }
value = TAILQ_LAST(&entry->values, args_values);
ll = strtonum(entry->value, minval, maxval, &errstr); ll = strtonum(value->value, minval, maxval, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
*cause = xstrdup(errstr); *cause = xstrdup(errstr);
return (0); return (0);

View File

@@ -23,22 +23,28 @@
#include "tmux.h" #include "tmux.h"
const char * const char *
attributes_tostring(u_char attr) attributes_tostring(int attr)
{ {
static char buf[128]; static char buf[512];
size_t len; size_t len;
if (attr == 0) if (attr == 0)
return ("none"); return ("none");
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s", len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s",
attr & GRID_ATTR_BRIGHT ? "bright," : "", (attr & GRID_ATTR_BRIGHT) ? "bright," : "",
attr & GRID_ATTR_DIM ? "dim," : "", (attr & GRID_ATTR_DIM) ? "dim," : "",
attr & GRID_ATTR_UNDERSCORE ? "underscore," : "", (attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "",
attr & GRID_ATTR_BLINK ? "blink," : "", (attr & GRID_ATTR_BLINK)? "blink," : "",
attr & GRID_ATTR_REVERSE ? "reverse," : "", (attr & GRID_ATTR_REVERSE) ? "reverse," : "",
attr & GRID_ATTR_HIDDEN ? "hidden," : "", (attr & GRID_ATTR_HIDDEN) ? "hidden," : "",
attr & GRID_ATTR_ITALICS ? "italics," : ""); (attr & GRID_ATTR_ITALICS) ? "italics," : "",
(attr & GRID_ATTR_STRIKETHROUGH) ? "strikethrough," : "",
(attr & GRID_ATTR_UNDERSCORE_2) ? "double-underscore," : "",
(attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "",
(attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "",
(attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "",
(attr & GRID_ATTR_OVERLINE) ? "overline," : "");
if (len > 0) if (len > 0)
buf[len - 1] = '\0'; buf[len - 1] = '\0';
@@ -49,8 +55,28 @@ int
attributes_fromstring(const char *str) attributes_fromstring(const char *str)
{ {
const char delimiters[] = " ,|"; const char delimiters[] = " ,|";
u_char attr; int attr;
size_t end; size_t end;
u_int i;
struct {
const char* name;
int attr;
} table[] = {
{ "bright", GRID_ATTR_BRIGHT },
{ "bold", GRID_ATTR_BRIGHT },
{ "dim", GRID_ATTR_DIM },
{ "underscore", GRID_ATTR_UNDERSCORE },
{ "blink", GRID_ATTR_BLINK },
{ "reverse", GRID_ATTR_REVERSE },
{ "hidden", GRID_ATTR_HIDDEN },
{ "italics", GRID_ATTR_ITALICS },
{ "strikethrough", GRID_ATTR_STRIKETHROUGH },
{ "double-underscore", GRID_ATTR_UNDERSCORE_2 },
{ "curly-underscore", GRID_ATTR_UNDERSCORE_3 },
{ "dotted-underscore", GRID_ATTR_UNDERSCORE_4 },
{ "dashed-underscore", GRID_ATTR_UNDERSCORE_5 },
{ "overline", GRID_ATTR_OVERLINE }
};
if (*str == '\0' || strcspn(str, delimiters) == 0) if (*str == '\0' || strcspn(str, delimiters) == 0)
return (-1); return (-1);
@@ -63,22 +89,15 @@ attributes_fromstring(const char *str)
attr = 0; attr = 0;
do { do {
end = strcspn(str, delimiters); end = strcspn(str, delimiters);
if ((end == 6 && strncasecmp(str, "bright", end) == 0) || for (i = 0; i < nitems(table); i++) {
(end == 4 && strncasecmp(str, "bold", end) == 0)) if (end != strlen(table[i].name))
attr |= GRID_ATTR_BRIGHT; continue;
else if (end == 3 && strncasecmp(str, "dim", end) == 0) if (strncasecmp(str, table[i].name, end) == 0) {
attr |= GRID_ATTR_DIM; attr |= table[i].attr;
else if (end == 10 && strncasecmp(str, "underscore", end) == 0) break;
attr |= GRID_ATTR_UNDERSCORE; }
else if (end == 5 && strncasecmp(str, "blink", end) == 0) }
attr |= GRID_ATTR_BLINK; if (i == nitems(table))
else if (end == 7 && strncasecmp(str, "reverse", end) == 0)
attr |= GRID_ATTR_REVERSE;
else if (end == 6 && strncasecmp(str, "hidden", end) == 0)
attr |= GRID_ATTR_HIDDEN;
else if (end == 7 && strncasecmp(str, "italics", end) == 0)
attr |= GRID_ATTR_ITALICS;
else
return (-1); return (-1);
str += end + strspn(str + end, delimiters); str += end + strspn(str + end, delimiters);
} while (*str != '\0'); } while (*str != '\0');

View File

@@ -1,8 +1,8 @@
#!/bin/sh #!/bin/sh
if [ "x$(uname)" = "xOpenBSD" ]; then if [ "x$(uname)" = "xOpenBSD" ]; then
[ -z "$AUTOMAKE_VERSION" ] && export AUTOMAKE_VERSION=1.10 [ -z "$AUTOMAKE_VERSION" ] && export AUTOMAKE_VERSION=1.15
[ -z "$AUTOCONF_VERSION" ] && export AUTOCONF_VERSION=2.65 [ -z "$AUTOCONF_VERSION" ] && export AUTOCONF_VERSION=2.69
fi fi
die() die()

194
cfg.c
View File

@@ -23,19 +23,41 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
char *cfg_file; struct client *cfg_client;
struct cmd_q *cfg_cmd_q; static char *cfg_file;
int cfg_finished; int cfg_finished;
int cfg_references; static char **cfg_causes;
char **cfg_causes; static u_int cfg_ncauses;
u_int cfg_ncauses; static struct cmdq_item *cfg_item;
struct client *cfg_client;
void cfg_default_done(struct cmd_q *); static enum cmd_retval
cfg_client_done(__unused struct cmdq_item *item, __unused void *data)
{
if (!cfg_finished)
return (CMD_RETURN_WAIT);
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cfg_done(__unused struct cmdq_item *item, __unused void *data)
{
if (cfg_finished)
return (CMD_RETURN_NORMAL);
cfg_finished = 1;
if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions));
if (cfg_item != NULL)
cmdq_continue(cfg_item);
status_prompt_load_history();
return (CMD_RETURN_NORMAL);
}
void void
set_cfg_file(const char *path) set_cfg_file(const char *path)
@@ -48,109 +70,89 @@ void
start_cfg(void) start_cfg(void)
{ {
const char *home; const char *home;
int quiet = 0; int flags = 0;
struct client *c;
cfg_cmd_q = cmdq_new(NULL); /*
cfg_cmd_q->emptyfn = cfg_default_done; * Configuration files are loaded without a client, so commands are run
* in the global queue with item->client NULL.
*
* However, we must block the initial client (but just the initial
* client) so that its command runs after the configuration is loaded.
* Because start_cfg() is called so early, we can be sure the client's
* command queue is currently empty and our callback will be at the
* front - we need to get in before MSG_COMMAND.
*/
cfg_client = c = TAILQ_FIRST(&clients);
if (c != NULL) {
cfg_item = cmdq_get_callback(cfg_client_done, NULL);
cmdq_append(c, cfg_item);
}
cfg_finished = 0; if (cfg_file == NULL)
cfg_references = 1; load_cfg(TMUX_CONF, c, NULL, CMD_PARSE_QUIET, NULL);
cfg_client = TAILQ_FIRST(&clients);
if (cfg_client != NULL)
cfg_client->references++;
load_cfg(TMUX_CONF, cfg_cmd_q, 1);
if (cfg_file == NULL && (home = find_home()) != NULL) { if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmux.conf", home); xasprintf(&cfg_file, "%s/.tmux.conf", home);
quiet = 1; flags = CMD_PARSE_QUIET;
} }
if (cfg_file != NULL) if (cfg_file != NULL)
load_cfg(cfg_file, cfg_cmd_q, quiet); load_cfg(cfg_file, c, NULL, flags, NULL);
cmdq_continue(cfg_cmd_q); cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
} }
int int
load_cfg(const char *path, struct cmd_q *cmdq, int quiet) load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
struct cmdq_item **new_item)
{ {
FILE *f; FILE *f;
char delim[3] = { '\\', '\\', '\0' }; struct cmd_parse_input pi;
u_int found; struct cmd_parse_result *pr;
size_t line = 0; struct cmdq_item *new_item0;
char *buf, *cause1, *p;
struct cmd_list *cmdlist; if (new_item != NULL)
*new_item = NULL;
log_debug("loading %s", path); log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) { if ((f = fopen(path, "rb")) == NULL) {
if (errno == ENOENT && quiet) if (errno == ENOENT && (flags & CMD_PARSE_QUIET))
return (0); return (0);
cfg_add_cause("%s: %s", path, strerror(errno)); cfg_add_cause("%s: %s", path, strerror(errno));
return (-1); return (-1);
} }
found = 0; memset(&pi, 0, sizeof pi);
while ((buf = fparseln(f, NULL, &line, delim, 0)) != NULL) { pi.flags = flags;
log_debug("%s: %s", path, buf); pi.file = path;
pi.line = 1;
pi.item = item;
pi.c = c;
/* Skip empty lines. */ pr = cmd_parse_from_file(f, &pi);
p = buf;
while (isspace((u_char) *p))
p++;
if (*p == '\0') {
free(buf);
continue;
}
/* Parse and run the command. */
if (cmd_string_parse(p, &cmdlist, path, line, &cause1) != 0) {
free(buf);
if (cause1 == NULL)
continue;
cfg_add_cause("%s:%zu: %s", path, line, cause1);
free(cause1);
continue;
}
free(buf);
if (cmdlist == NULL)
continue;
cmdq_append(cmdq, cmdlist, NULL);
cmd_list_free(cmdlist);
found++;
}
fclose(f); fclose(f);
if (pr->status == CMD_PARSE_EMPTY)
return (found); return (0);
} if (pr->status == CMD_PARSE_ERROR) {
cfg_add_cause("%s", pr->error);
void free(pr->error);
cfg_default_done(__unused struct cmd_q *cmdq) return (-1);
{
if (--cfg_references != 0)
return;
cfg_finished = 1;
if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions));
cmdq_free(cfg_cmd_q);
cfg_cmd_q = NULL;
if (cfg_client != NULL) {
/*
* The client command queue starts with client_exit set to 1 so
* only continue if not empty (that is, we have been delayed
* during configuration parsing for long enough that the
* MSG_COMMAND has arrived), else the client will exit before
* the MSG_COMMAND which might tell it not to.
*/
if (!TAILQ_EMPTY(&cfg_client->cmdq->queue))
cmdq_continue(cfg_client->cmdq);
server_client_unref(cfg_client);
cfg_client = NULL;
} }
if (flags & CMD_PARSE_PARSEONLY) {
cmd_list_free(pr->cmdlist);
return (0);
}
new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
if (item != NULL)
cmdq_insert_after(item, new_item0);
else
cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist);
if (new_item != NULL)
*new_item = new_item0;
return (0);
} }
void void
@@ -169,12 +171,12 @@ cfg_add_cause(const char *fmt, ...)
} }
void void
cfg_print_causes(struct cmd_q *cmdq) cfg_print_causes(struct cmdq_item *item)
{ {
u_int i; u_int i;
for (i = 0; i < cfg_ncauses; i++) { for (i = 0; i < cfg_ncauses; i++) {
cmdq_print(cmdq, "%s", cfg_causes[i]); cmdq_print(item, "%s", cfg_causes[i]);
free(cfg_causes[i]); free(cfg_causes[i]);
} }
@@ -186,15 +188,17 @@ cfg_print_causes(struct cmd_q *cmdq)
void void
cfg_show_causes(struct session *s) cfg_show_causes(struct session *s)
{ {
struct window_pane *wp; struct window_pane *wp;
u_int i; struct window_mode_entry *wme;
u_int i;
if (s == NULL || cfg_ncauses == 0) if (s == NULL || cfg_ncauses == 0)
return; return;
wp = s->curw->window->active; wp = s->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode); wme = TAILQ_FIRST(&wp->modes);
window_copy_init_for_output(wp); if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
for (i = 0; i < cfg_ncauses; i++) { for (i = 0; i < cfg_ncauses; i++) {
window_copy_add(wp, "%s", cfg_causes[i]); window_copy_add(wp, "%s", cfg_causes[i]);
free(cfg_causes[i]); free(cfg_causes[i]);

157
client.c
View File

@@ -17,11 +17,10 @@
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h> #include <sys/un.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/file.h>
#include <errno.h> #include <errno.h>
#include <event.h> #include <event.h>
@@ -33,11 +32,11 @@
#include "tmux.h" #include "tmux.h"
struct tmuxproc *client_proc; static struct tmuxproc *client_proc;
struct tmuxpeer *client_peer; static struct tmuxpeer *client_peer;
int client_flags; static int client_flags;
struct event client_stdin; static struct event client_stdin;
enum { static enum {
CLIENT_EXIT_NONE, CLIENT_EXIT_NONE,
CLIENT_EXIT_DETACHED, CLIENT_EXIT_DETACHED,
CLIENT_EXIT_DETACHED_HUP, CLIENT_EXIT_DETACHED_HUP,
@@ -47,29 +46,31 @@ enum {
CLIENT_EXIT_EXITED, CLIENT_EXIT_EXITED,
CLIENT_EXIT_SERVER_EXITED, CLIENT_EXIT_SERVER_EXITED,
} client_exitreason = CLIENT_EXIT_NONE; } client_exitreason = CLIENT_EXIT_NONE;
int client_exitval; static int client_exitval;
enum msgtype client_exittype; static enum msgtype client_exittype;
const char *client_exitsession; static const char *client_exitsession;
int client_attached; static const char *client_execshell;
static const char *client_execcmd;
static int client_attached;
__dead void client_exec(const char *,const char *); static __dead void client_exec(const char *,const char *);
int client_get_lock(char *); static int client_get_lock(char *);
int client_connect(struct event_base *, const char *, int); static int client_connect(struct event_base *, const char *, int);
void client_send_identify(const char *, const char *); static void client_send_identify(const char *, const char *);
void client_stdin_callback(int, short, void *); static void client_stdin_callback(int, short, void *);
void client_write(int, const char *, size_t); static void client_write(int, const char *, size_t);
void client_signal(int); static void client_signal(int);
void client_dispatch(struct imsg *, void *); static void client_dispatch(struct imsg *, void *);
void client_dispatch_attached(struct imsg *); static void client_dispatch_attached(struct imsg *);
void client_dispatch_wait(struct imsg *, const char *); static void client_dispatch_wait(struct imsg *);
const char *client_exit_message(void); static const char *client_exit_message(void);
/* /*
* Get server create lock. If already held then server start is happening in * Get server create lock. If already held then server start is happening in
* another client, so block until the lock is released and return -2 to * another client, so block until the lock is released and return -2 to
* retry. Return -1 on failure to continue and start the server anyway. * retry. Return -1 on failure to continue and start the server anyway.
*/ */
int static int
client_get_lock(char *lockfile) client_get_lock(char *lockfile)
{ {
int lockfd; int lockfd;
@@ -96,7 +97,7 @@ client_get_lock(char *lockfile)
} }
/* Connect client to server. */ /* Connect client to server. */
int static int
client_connect(struct event_base *base, const char *path, int start_server) client_connect(struct event_base *base, const char *path, int start_server)
{ {
struct sockaddr_un sa; struct sockaddr_un sa;
@@ -154,7 +155,7 @@ retry:
close(lockfd); close(lockfd);
return (-1); return (-1);
} }
fd = server_start(base, lockfd, lockfile); fd = server_start(client_proc, base, lockfd, lockfile);
} }
if (locked && lockfd >= 0) { if (locked && lockfd >= 0) {
@@ -201,7 +202,7 @@ client_exit_message(void)
case CLIENT_EXIT_TERMINATED: case CLIENT_EXIT_TERMINATED:
return ("terminated"); return ("terminated");
case CLIENT_EXIT_LOST_SERVER: case CLIENT_EXIT_LOST_SERVER:
return ("lost server"); return ("server exited unexpectedly");
case CLIENT_EXIT_EXITED: case CLIENT_EXIT_EXITED:
return ("exited"); return ("exited");
case CLIENT_EXIT_SERVER_EXITED: case CLIENT_EXIT_SERVER_EXITED:
@@ -212,17 +213,15 @@ client_exit_message(void)
/* Client main loop. */ /* Client main loop. */
int int
client_main(struct event_base *base, int argc, char **argv, int flags, client_main(struct event_base *base, int argc, char **argv, int flags)
const char *shellcmd)
{ {
struct cmd_parse_result *pr;
struct cmd *cmd; struct cmd *cmd;
struct cmd_list *cmdlist;
struct msg_command_data *data; struct msg_command_data *data;
int cmdflags, fd, i; int cmdflags, fd, i;
const char *ttynam, *cwd; const char *ttynam, *cwd;
pid_t ppid; pid_t ppid;
enum msgtype msg; enum msgtype msg;
char *cause, path[PATH_MAX];
struct termios tio, saved_tio; struct termios tio, saved_tio;
size_t size; size_t size;
@@ -234,7 +233,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
/* Set up the initial command. */ /* Set up the initial command. */
cmdflags = 0; cmdflags = 0;
if (shellcmd != NULL) { if (shell_command != NULL) {
msg = MSG_SHELL; msg = MSG_SHELL;
cmdflags = CMD_STARTSERVER; cmdflags = CMD_STARTSERVER;
} else if (argc == 0) { } else if (argc == 0) {
@@ -248,21 +247,20 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
* later in server) but it is necessary to get the start server * later in server) but it is necessary to get the start server
* flag. * flag.
*/ */
cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause); pr = cmd_parse_from_arguments(argc, argv, NULL);
if (cmdlist == NULL) { if (pr->status == CMD_PARSE_SUCCESS) {
fprintf(stderr, "%s\n", cause); TAILQ_FOREACH(cmd, &pr->cmdlist->list, qentry) {
return (1); if (cmd->entry->flags & CMD_STARTSERVER)
} cmdflags |= CMD_STARTSERVER;
cmdflags &= ~CMD_STARTSERVER; }
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { cmd_list_free(pr->cmdlist);
if (cmd->entry->flags & CMD_STARTSERVER) } else
cmdflags |= CMD_STARTSERVER; free(pr->error);
}
cmd_list_free(cmdlist);
} }
/* Create client process structure (starts logging). */ /* Create client process structure (starts logging). */
client_proc = proc_start("client", base, 0, client_signal); client_proc = proc_start("client");
proc_set_signals(client_proc, client_signal);
/* Initialize the client socket and start the server. */ /* Initialize the client socket and start the server. */
fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER); fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
@@ -276,18 +274,14 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
} }
return (1); return (1);
} }
client_peer = proc_add_peer(client_proc, fd, client_dispatch, client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL);
(void *)shellcmd);
/* Save these before pledge(). */ /* Save these before pledge(). */
if ((cwd = getcwd(path, sizeof path)) == NULL) { if ((cwd = find_cwd()) == NULL && (cwd = find_home()) == NULL)
if ((cwd = find_home()) == NULL) cwd = "/";
cwd = "/";
}
if ((ttynam = ttyname(STDIN_FILENO)) == NULL) if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
ttynam = ""; ttynam = "";
#ifdef __OpenBSD__
/* /*
* Drop privileges for client. "proc exec" is needed for -c and for * Drop privileges for client. "proc exec" is needed for -c and for
* locking (which uses system(3)). * locking (which uses system(3)).
@@ -299,9 +293,10 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
*/ */
if (pledge("stdio unix sendfd proc exec tty", NULL) != 0) if (pledge("stdio unix sendfd proc exec tty", NULL) != 0)
fatal("pledge failed"); fatal("pledge failed");
#endif
/* Free stuff that is not used in the client. */ /* Free stuff that is not used in the client. */
if (ptm_fd != -1)
close(ptm_fd);
options_free(global_options); options_free(global_options);
options_free(global_s_options); options_free(global_s_options);
options_free(global_w_options); options_free(global_w_options);
@@ -312,8 +307,11 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST, event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
client_stdin_callback, NULL); client_stdin_callback, NULL);
if (client_flags & CLIENT_CONTROLCONTROL) { if (client_flags & CLIENT_CONTROLCONTROL) {
if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) {
fatal("tcgetattr failed"); fprintf(stderr, "tcgetattr failed: %s\n",
strerror(errno));
return (1);
}
cfmakeraw(&tio); cfmakeraw(&tio);
tio.c_iflag = ICRNL|IXANY; tio.c_iflag = ICRNL|IXANY;
tio.c_oflag = OPOST|ONLCR; tio.c_oflag = OPOST|ONLCR;
@@ -337,6 +335,10 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
size = 0; size = 0;
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
size += strlen(argv[i]) + 1; size += strlen(argv[i]) + 1;
if (size > MAX_IMSGSIZE - (sizeof *data)) {
fprintf(stderr, "command too long\n");
return (1);
}
data = xmalloc((sizeof *data) + size); data = xmalloc((sizeof *data) + size);
/* Prepare command for server. */ /* Prepare command for server. */
@@ -361,6 +363,13 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
/* Start main loop. */ /* Start main loop. */
proc_loop(client_proc, NULL); proc_loop(client_proc, NULL);
/* Run command if user requested exec, instead of exiting. */
if (client_exittype == MSG_EXEC) {
if (client_flags & CLIENT_CONTROLCONTROL)
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
client_exec(client_execshell, client_execcmd);
}
/* Print the exit message, if any, and exit. */ /* Print the exit message, if any, and exit. */
if (client_attached) { if (client_attached) {
if (client_exitreason != CLIENT_EXIT_NONE) if (client_exitreason != CLIENT_EXIT_NONE)
@@ -383,7 +392,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
} }
/* Send identify messages to server. */ /* Send identify messages to server. */
void static void
client_send_identify(const char *ttynam, const char *cwd) client_send_identify(const char *ttynam, const char *cwd)
{ {
const char *s; const char *s;
@@ -420,14 +429,14 @@ client_send_identify(const char *ttynam, const char *cwd)
} }
/* Callback for client stdin read events. */ /* Callback for client stdin read events. */
void static void
client_stdin_callback(__unused int fd, __unused short events, client_stdin_callback(__unused int fd, __unused short events,
__unused void *arg) __unused void *arg)
{ {
struct msg_stdin_data data; struct msg_stdin_data data;
data.size = read(STDIN_FILENO, data.data, sizeof data.data); data.size = read(STDIN_FILENO, data.data, sizeof data.data);
if (data.size < 0 && (errno == EINTR || errno == EAGAIN)) if (data.size == -1 && (errno == EINTR || errno == EAGAIN))
return; return;
proc_send(client_peer, MSG_STDIN, -1, &data, sizeof data); proc_send(client_peer, MSG_STDIN, -1, &data, sizeof data);
@@ -436,11 +445,12 @@ client_stdin_callback(__unused int fd, __unused short events,
} }
/* Force write to file descriptor. */ /* Force write to file descriptor. */
void static void
client_write(int fd, const char *data, size_t size) client_write(int fd, const char *data, size_t size)
{ {
ssize_t used; ssize_t used;
log_debug("%s: %.*s", __func__, (int)size, data);
while (size != 0) { while (size != 0) {
used = write(fd, data, size); used = write(fd, data, size);
if (used == -1) { if (used == -1) {
@@ -454,7 +464,7 @@ client_write(int fd, const char *data, size_t size)
} }
/* Run command in shell; used for -c. */ /* Run command in shell; used for -c. */
__dead void static __dead void
client_exec(const char *shell, const char *shellcmd) client_exec(const char *shell, const char *shellcmd)
{ {
const char *name, *ptr; const char *name, *ptr;
@@ -473,6 +483,8 @@ client_exec(const char *shell, const char *shellcmd)
xasprintf(&argv0, "%s", name); xasprintf(&argv0, "%s", name);
setenv("SHELL", shell, 1); setenv("SHELL", shell, 1);
proc_clear_signals(client_proc, 1);
setblocking(STDIN_FILENO, 1); setblocking(STDIN_FILENO, 1);
setblocking(STDOUT_FILENO, 1); setblocking(STDOUT_FILENO, 1);
setblocking(STDERR_FILENO, 1); setblocking(STDERR_FILENO, 1);
@@ -483,7 +495,7 @@ client_exec(const char *shell, const char *shellcmd)
} }
/* Callback to handle signals in the client. */ /* Callback to handle signals in the client. */
void static void
client_signal(int sig) client_signal(int sig)
{ {
struct sigaction sigact; struct sigaction sigact;
@@ -523,8 +535,8 @@ client_signal(int sig)
} }
/* Callback for client read events. */ /* Callback for client read events. */
void static void
client_dispatch(struct imsg *imsg, void *arg) client_dispatch(struct imsg *imsg, __unused void *arg)
{ {
if (imsg == NULL) { if (imsg == NULL) {
client_exitreason = CLIENT_EXIT_LOST_SERVER; client_exitreason = CLIENT_EXIT_LOST_SERVER;
@@ -536,19 +548,18 @@ client_dispatch(struct imsg *imsg, void *arg)
if (client_attached) if (client_attached)
client_dispatch_attached(imsg); client_dispatch_attached(imsg);
else else
client_dispatch_wait(imsg, arg); client_dispatch_wait(imsg);
} }
/* Dispatch imsgs when in wait state (before MSG_READY). */ /* Dispatch imsgs when in wait state (before MSG_READY). */
void static void
client_dispatch_wait(struct imsg *imsg, const char *shellcmd) client_dispatch_wait(struct imsg *imsg)
{ {
char *data; char *data;
ssize_t datalen; ssize_t datalen;
struct msg_stdout_data stdoutdata; struct msg_stdout_data stdoutdata;
struct msg_stderr_data stderrdata; struct msg_stderr_data stderrdata;
int retval; int retval;
#ifdef __OpenBSD__
static int pledge_applied; static int pledge_applied;
/* /*
@@ -562,7 +573,6 @@ client_dispatch_wait(struct imsg *imsg, const char *shellcmd)
fatal("pledge failed"); fatal("pledge failed");
pledge_applied = 1; pledge_applied = 1;
}; };
#endif
data = imsg->data; data = imsg->data;
datalen = imsg->hdr.len - IMSG_HEADER_SIZE; datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
@@ -622,8 +632,7 @@ client_dispatch_wait(struct imsg *imsg, const char *shellcmd)
if (datalen == 0 || data[datalen - 1] != '\0') if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_SHELL string"); fatalx("bad MSG_SHELL string");
clear_signals(0); client_exec(data, shell_command);
client_exec(data, shellcmd);
/* NOTREACHED */ /* NOTREACHED */
case MSG_DETACH: case MSG_DETACH:
case MSG_DETACHKILL: case MSG_DETACHKILL:
@@ -636,7 +645,7 @@ client_dispatch_wait(struct imsg *imsg, const char *shellcmd)
} }
/* Dispatch imsgs in attached state (after MSG_READY). */ /* Dispatch imsgs in attached state (after MSG_READY). */
void static void
client_dispatch_attached(struct imsg *imsg) client_dispatch_attached(struct imsg *imsg)
{ {
struct sigaction sigact; struct sigaction sigact;
@@ -660,6 +669,16 @@ client_dispatch_attached(struct imsg *imsg)
client_exitreason = CLIENT_EXIT_DETACHED; client_exitreason = CLIENT_EXIT_DETACHED;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0); proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break; break;
case MSG_EXEC:
if (datalen == 0 || data[datalen - 1] != '\0' ||
strlen(data) + 1 == (size_t)datalen)
fatalx("bad MSG_EXEC string");
client_execcmd = xstrdup(data);
client_execshell = xstrdup(data + strlen(data) + 1);
client_exittype = imsg->hdr.type;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
case MSG_EXIT: case MSG_EXIT:
if (datalen != 0 && datalen != sizeof (int)) if (datalen != 0 && datalen != sizeof (int))
fatalx("bad MSG_EXIT size"); fatalx("bad MSG_EXIT size");

View File

@@ -30,113 +30,131 @@
* Attach existing session to the current terminal. * Attach existing session to the current terminal.
*/ */
enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_attach_session_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_attach_session_entry = { const struct cmd_entry cmd_attach_session_entry = {
.name = "attach-session", .name = "attach-session",
.alias = "attach", .alias = "attach",
.args = { "c:dErt:", 0, 0 }, .args = { "c:dErt:x", 0, 0 },
.usage = "[-dEr] [-c working-directory] " CMD_TARGET_SESSION_USAGE, .usage = "[-dErx] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION_WITHPANE, /* -t is special */
.flags = CMD_STARTSERVER, .flags = CMD_STARTSERVER,
.exec = cmd_attach_session_exec .exec = cmd_attach_session_exec
}; };
enum cmd_retval enum cmd_retval
cmd_attach_session(struct cmd_q *cmdq, int dflag, int rflag, const char *cflag, cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
int Eflag) int xflag, int rflag, const char *cflag, int Eflag)
{ {
struct session *s = cmdq->state.tflag.s; struct cmd_find_state *current = &item->shared->current;
struct client *c = cmdq->client, *c_loop; enum cmd_find_type type;
struct winlink *wl = cmdq->state.tflag.wl; int flags;
struct window_pane *wp = cmdq->state.tflag.wp; struct client *c = item->client, *c_loop;
const char *update; struct session *s;
char *cause, *cwd; struct winlink *wl;
struct format_tree *ft; struct window_pane *wp;
char *cause;
enum msgtype msgtype;
if (RB_EMPTY(&sessions)) { if (RB_EMPTY(&sessions)) {
cmdq_error(cmdq, "no sessions"); cmdq_error(item, "no sessions");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (c == NULL) if (c == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (server_client_check_nested(c)) { if (server_client_check_nested(c)) {
cmdq_error(cmdq, "sessions should be nested with care, " cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force"); "unset $TMUX to force");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (tflag != NULL && tflag[strcspn(tflag, ":.")] != '\0') {
type = CMD_FIND_PANE;
flags = 0;
} else {
type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED;
}
if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR);
s = item->target.s;
wl = item->target.wl;
wp = item->target.wp;
if (wl != NULL) { if (wl != NULL) {
if (wp != NULL) if (wp != NULL)
window_set_active_pane(wp->window, wp); window_set_active_pane(wp->window, wp, 1);
session_set_current(s, wl); session_set_current(s, wl);
if (wp != NULL)
cmd_find_from_winlink_pane(current, wl, wp, 0);
else
cmd_find_from_winlink(current, wl, 0);
} }
if (cflag != NULL) { if (cflag != NULL) {
ft = format_create(cmdq, 0);
format_defaults(ft, c, s, wl, wp);
cwd = format_expand(ft, cflag);
format_free(ft);
free((void *)s->cwd); free((void *)s->cwd);
s->cwd = cwd; s->cwd = format_single(item, cflag, c, s, wl, wp);
} }
c->last_session = c->session;
if (c->session != NULL) { if (c->session != NULL) {
if (dflag) { if (dflag || xflag) {
if (xflag)
msgtype = MSG_DETACHKILL;
else
msgtype = MSG_DETACH;
TAILQ_FOREACH(c_loop, &clients, entry) { TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session != s || c == c_loop) if (c_loop->session != s || c == c_loop)
continue; continue;
server_client_detach(c_loop, MSG_DETACH); server_client_detach(c_loop, msgtype);
} }
} }
if (!Eflag)
if (!Eflag) { environ_update(s->options, c->environ, s->environ);
update = options_get_string(s->options,
"update-environment");
environ_update(update, c->environ, s->environ);
}
c->session = s; c->session = s;
server_client_set_key_table(c, NULL); if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c); status_timer_start(c);
notify_attached_session_changed(c); notify_client("client-session-changed", c);
session_update_activity(s, NULL); session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL); gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c); server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS; s->curw->flags &= ~WINLINK_ALERTFLAGS;
} else { } else {
if (server_client_open(c, &cause) != 0) { if (server_client_open(c, &cause) != 0) {
cmdq_error(cmdq, "open terminal failed: %s", cause); cmdq_error(item, "open terminal failed: %s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (rflag) if (rflag)
c->flags |= CLIENT_READONLY; c->flags |= CLIENT_READONLY;
if (dflag) { if (dflag || xflag) {
if (xflag)
msgtype = MSG_DETACHKILL;
else
msgtype = MSG_DETACH;
TAILQ_FOREACH(c_loop, &clients, entry) { TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session != s || c == c_loop) if (c_loop->session != s || c == c_loop)
continue; continue;
server_client_detach(c_loop, MSG_DETACH); server_client_detach(c_loop, msgtype);
} }
} }
if (!Eflag)
if (!Eflag) { environ_update(s->options, c->environ, s->environ);
update = options_get_string(s->options,
"update-environment");
environ_update(update, c->environ, s->environ);
}
c->session = s; c->session = s;
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c); status_timer_start(c);
notify_attached_session_changed(c); notify_client("client-session-changed", c);
session_update_activity(s, NULL); session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL); gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c); server_redraw_client(c);
@@ -144,8 +162,8 @@ cmd_attach_session(struct cmd_q *cmdq, int dflag, int rflag, const char *cflag,
if (~c->flags & CLIENT_CONTROL) if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0); proc_send(c->peer, MSG_READY, -1, NULL, 0);
hooks_run(c->session->hooks, c, NULL, "client-attached"); notify_client("client-attached", c);
cmdq->client_exit = 0; c->flags |= CLIENT_ATTACHED;
} }
recalculate_sizes(); recalculate_sizes();
alerts_check_session(s); alerts_check_session(s);
@@ -154,11 +172,12 @@ cmd_attach_session(struct cmd_q *cmdq, int dflag, int rflag, const char *cflag,
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
enum cmd_retval static enum cmd_retval
cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq) cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
return (cmd_attach_session(cmdq, args_has(args, 'd'), return (cmd_attach_session(item, args_get(args, 't'),
args_has(args, 'r'), args_get(args, 'c'), args_has(args, 'E'))); args_has(args, 'd'), args_has(args, 'x'), args_has(args, 'r'),
args_get(args, 'c'), args_has(args, 'E')));
} }

View File

@@ -24,56 +24,39 @@
#include "tmux.h" #include "tmux.h"
/* /*
* Bind a key to a command, this recurses through cmd_*. * Bind a key to a command.
*/ */
enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmdq_item *);
enum cmd_retval cmd_bind_key_mode_table(struct cmd *, struct cmd_q *,
key_code);
const struct cmd_entry cmd_bind_key_entry = { const struct cmd_entry cmd_bind_key_entry = {
.name = "bind-key", .name = "bind-key",
.alias = "bind", .alias = "bind",
.args = { "cnrR:t:T:", 1, -1 }, .args = { "cnrT:", 2, -1 },
.usage = "[-cnr] [-t mode-table] [-R repeat-count] [-T key-table] key " .usage = "[-cnr] [-T key-table] key "
"command [arguments]", "command [arguments]",
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_bind_key_exec .exec = cmd_bind_key_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq) cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
char *cause; key_code key;
struct cmd_list *cmdlist; const char *tablename;
key_code key; struct cmd_parse_result *pr;
const char *tablename; char **argv = args->argv;
int argc = args->argc;
if (args_has(args, 't')) { key = key_string_lookup_string(argv[0]);
if (args->argc != 2 && args->argc != 3) {
cmdq_error(cmdq, "not enough arguments");
return (CMD_RETURN_ERROR);
}
} else {
if (args->argc < 2) {
cmdq_error(cmdq, "not enough arguments");
return (CMD_RETURN_ERROR);
}
}
key = key_string_lookup_string(args->argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) { if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
cmdq_error(cmdq, "unknown key: %s", args->argv[0]); cmdq_error(item, "unknown key: %s", argv[0]);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 't'))
return (cmd_bind_key_mode_table(self, cmdq, key));
if (args_has(args, 'T')) if (args_has(args, 'T'))
tablename = args_get(args, 'T'); tablename = args_get(args, 'T');
else if (args_has(args, 'n')) else if (args_has(args, 'n'))
@@ -81,91 +64,21 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
else else
tablename = "prefix"; tablename = "prefix";
cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0, if (argc == 2)
&cause); pr = cmd_parse_from_string(argv[1], NULL);
if (cmdlist == NULL) { else
cmdq_error(cmdq, "%s", cause); pr = cmd_parse_from_arguments(argc - 1, argv + 1, NULL);
free(cause); switch (pr->status) {
case CMD_PARSE_EMPTY:
cmdq_error(item, "empty command");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
case CMD_PARSE_ERROR:
cmdq_error(item, "%s", pr->error);
free(pr->error);
return (CMD_RETURN_ERROR);
case CMD_PARSE_SUCCESS:
break;
} }
key_bindings_add(tablename, key, args_has(args, 'r'), pr->cmdlist);
key_bindings_add(tablename, key, args_has(args, 'r'), cmdlist);
return (CMD_RETURN_NORMAL);
}
enum cmd_retval
cmd_bind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, key_code key)
{
struct args *args = self->args;
const char *tablename, *arg;
const struct mode_key_table *mtab;
struct mode_key_binding *mbind, mtmp;
enum mode_key_cmd cmd;
char *cause;
u_int repeat;
tablename = args_get(args, 't');
if ((mtab = mode_key_findtable(tablename)) == NULL) {
cmdq_error(cmdq, "unknown key table: %s", tablename);
return (CMD_RETURN_ERROR);
}
cmd = mode_key_fromstring(mtab->cmdstr, args->argv[1]);
if (cmd == MODEKEY_NONE) {
cmdq_error(cmdq, "unknown command: %s", args->argv[1]);
return (CMD_RETURN_ERROR);
}
switch (cmd) {
case MODEKEYCOPY_APPENDSELECTION:
case MODEKEYCOPY_COPYSELECTION:
case MODEKEYCOPY_STARTNAMEDBUFFER:
if (args->argc == 2)
arg = NULL;
else {
arg = args->argv[2];
if (strcmp(arg, "-x") != 0) {
cmdq_error(cmdq, "unknown argument");
return (CMD_RETURN_ERROR);
}
}
break;
case MODEKEYCOPY_COPYPIPE:
if (args->argc != 3) {
cmdq_error(cmdq, "no argument given");
return (CMD_RETURN_ERROR);
}
arg = args->argv[2];
break;
default:
if (args->argc != 2) {
cmdq_error(cmdq, "no argument allowed");
return (CMD_RETURN_ERROR);
}
arg = NULL;
break;
}
repeat = 1;
if (args_has(args, 'R')) {
repeat = args_strtonum(args, 'R', 1, SHRT_MAX, &cause);
if (cause != NULL) {
cmdq_error(cmdq, "repeat count %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
mtmp.key = key;
mtmp.mode = !!args_has(args, 'c');
if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) == NULL) {
mbind = xmalloc(sizeof *mbind);
mbind->key = mtmp.key;
mbind->mode = mtmp.mode;
RB_INSERT(mode_key_tree, mtab->tree, mbind);
}
mbind->repeat = repeat;
mbind->cmd = cmd;
mbind->arg = arg != NULL ? xstrdup(arg) : NULL;
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -28,45 +28,46 @@
#define BREAK_PANE_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" #define BREAK_PANE_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
enum cmd_retval cmd_break_pane_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_break_pane_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_break_pane_entry = { const struct cmd_entry cmd_break_pane_entry = {
.name = "break-pane", .name = "break-pane",
.alias = "breakp", .alias = "breakp",
.args = { "dPF:s:t:", 0, 0 }, .args = { "dPF:n:s:t:", 0, 0 },
.usage = "[-dP] [-F format] [-s src-pane] [-t dst-window]", .usage = "[-dP] [-F format] [-n window-name] [-s src-pane] "
"[-t dst-window]",
.sflag = CMD_PANE, .source = { 's', CMD_FIND_PANE, 0 },
.tflag = CMD_WINDOW_INDEX, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
.flags = 0, .flags = 0,
.exec = cmd_break_pane_exec .exec = cmd_break_pane_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = cmdq->state.sflag.wl; struct cmd_find_state *current = &item->shared->current;
struct session *src_s = cmdq->state.sflag.s; struct client *c = cmd_find_client(item, NULL, 1);
struct session *dst_s = cmdq->state.tflag.s; struct winlink *wl = item->source.wl;
struct window_pane *wp = cmdq->state.sflag.wp; struct session *src_s = item->source.s;
struct session *dst_s = item->target.s;
struct window_pane *wp = item->source.wp;
struct window *w = wl->window; struct window *w = wl->window;
char *name; char *name, *cause;
char *cause; int idx = item->target.idx;
int idx = cmdq->state.tflag.idx;
struct format_tree *ft;
const char *template; const char *template;
char *cp; char *cp;
if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) { if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) {
cmdq_error(cmdq, "index %d already in use", idx); cmdq_error(item, "index %d already in use", idx);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (window_count_panes(w) == 1) { if (window_count_panes(w) == 1) {
cmdq_error(cmdq, "can't break with only one pane"); cmdq_error(item, "can't break with only one pane");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
server_unzoom_window(w); server_unzoom_window(w);
@@ -75,20 +76,31 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq)
window_lost_pane(w, wp); window_lost_pane(w, wp);
layout_close_pane(wp); layout_close_pane(wp);
w = wp->window = window_create1(dst_s->sx, dst_s->sy); w = wp->window = window_create(w->sx, w->sy);
options_set_parent(wp->options, w->options);
wp->flags |= PANE_STYLECHANGED;
TAILQ_INSERT_HEAD(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp; w->active = wp;
name = default_window_name(w);
window_set_name(w, name); if (!args_has(args, 'n')) {
free(name); name = default_window_name(w);
window_set_name(w, name);
free(name);
} else {
window_set_name(w, args_get(args, 'n'));
options_set_number(w->options, "automatic-rename", 0);
}
layout_init(w, wp); layout_init(w, wp);
wp->flags |= PANE_CHANGED; wp->flags |= PANE_CHANGED;
if (idx == -1) if (idx == -1)
idx = -1 - options_get_number(dst_s->options, "base-index"); idx = -1 - options_get_number(dst_s->options, "base-index");
wl = session_attach(dst_s, w, idx, &cause); /* can't fail */ wl = session_attach(dst_s, w, idx, &cause); /* can't fail */
if (!args_has(self->args, 'd')) if (!args_has(self->args, 'd')) {
session_select(dst_s, wl->idx); session_select(dst_s, wl->idx);
cmd_find_from_session(current, dst_s, 0);
}
server_redraw_session(src_s); server_redraw_session(src_s);
if (src_s != dst_s) if (src_s != dst_s)
@@ -100,15 +112,9 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = BREAK_PANE_TEMPLATE; template = BREAK_PANE_TEMPLATE;
cp = format_single(item, template, c, dst_s, wl, wp);
ft = format_create(cmdq, 0); cmdq_print(item, "%s", cp);
format_defaults(ft, cmdq->state.c, dst_s, wl, wp);
cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp);
free(cp); free(cp);
format_free(ft);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -27,12 +27,12 @@
* Write the entire contents of a pane to a buffer or stdout. * Write the entire contents of a pane to a buffer or stdout.
*/ */
enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmdq_item *);
char *cmd_capture_pane_append(char *, size_t *, char *, size_t); static char *cmd_capture_pane_append(char *, size_t *, char *, size_t);
char *cmd_capture_pane_pending(struct args *, struct window_pane *, static char *cmd_capture_pane_pending(struct args *, struct window_pane *,
size_t *); size_t *);
char *cmd_capture_pane_history(struct args *, struct cmd_q *, static char *cmd_capture_pane_history(struct args *, struct cmdq_item *,
struct window_pane *, size_t *); struct window_pane *, size_t *);
const struct cmd_entry cmd_capture_pane_entry = { const struct cmd_entry cmd_capture_pane_entry = {
@@ -41,15 +41,28 @@ const struct cmd_entry cmd_capture_pane_entry = {
.args = { "ab:CeE:JpPqS:t:", 0, 0 }, .args = { "ab:CeE:JpPqS:t:", 0, 0 },
.usage = "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] " .usage = "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] "
"[-S start-line]" CMD_TARGET_PANE_USAGE, "[-S start-line] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_capture_pane_exec .exec = cmd_capture_pane_exec
}; };
char * const struct cmd_entry cmd_clear_history_entry = {
.name = "clear-history",
.alias = "clearhist",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_capture_pane_exec
};
static char *
cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen) cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen)
{ {
buf = xrealloc(buf, *len + linelen + 1); buf = xrealloc(buf, *len + linelen + 1);
@@ -58,7 +71,7 @@ cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen)
return (buf); return (buf);
} }
char * static char *
cmd_capture_pane_pending(struct args *args, struct window_pane *wp, cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
size_t *len) size_t *len)
{ {
@@ -77,7 +90,7 @@ cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
buf = xstrdup(""); buf = xstrdup("");
if (args_has(args, 'C')) { if (args_has(args, 'C')) {
for (i = 0; i < linelen; i++) { for (i = 0; i < linelen; i++) {
if (line[i] >= ' ') { if (line[i] >= ' ' && line[i] != '\\') {
tmp[0] = line[i]; tmp[0] = line[i];
tmp[1] = '\0'; tmp[1] = '\0';
} else } else
@@ -90,8 +103,8 @@ cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
return (buf); return (buf);
} }
char * static char *
cmd_capture_pane_history(struct args *args, struct cmd_q *cmdq, cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
struct window_pane *wp, size_t *len) struct window_pane *wp, size_t *len)
{ {
struct grid *gd; struct grid *gd;
@@ -108,7 +121,7 @@ cmd_capture_pane_history(struct args *args, struct cmd_q *cmdq,
gd = wp->saved_grid; gd = wp->saved_grid;
if (gd == NULL) { if (gd == NULL) {
if (!args_has(args, 'q')) { if (!args_has(args, 'q')) {
cmdq_error(cmdq, "no alternate screen"); cmdq_error(item, "no alternate screen");
return (NULL); return (NULL);
} }
return (xstrdup("")); return (xstrdup(""));
@@ -175,29 +188,35 @@ cmd_capture_pane_history(struct args *args, struct cmd_q *cmdq,
return (buf); return (buf);
} }
enum cmd_retval static enum cmd_retval
cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c;
struct window_pane *wp = cmdq->state.tflag.wp; struct window_pane *wp = item->target.wp;
char *buf, *cause; char *buf, *cause;
const char *bufname; const char *bufname;
size_t len; size_t len;
if (self->entry == &cmd_clear_history_entry) {
window_pane_reset_mode_all(wp);
grid_clear_history(wp->base.grid);
return (CMD_RETURN_NORMAL);
}
len = 0; len = 0;
if (args_has(args, 'P')) if (args_has(args, 'P'))
buf = cmd_capture_pane_pending(args, wp, &len); buf = cmd_capture_pane_pending(args, wp, &len);
else else
buf = cmd_capture_pane_history(args, cmdq, wp, &len); buf = cmd_capture_pane_history(args, item, wp, &len);
if (buf == NULL) if (buf == NULL)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
if (args_has(args, 'p')) { if (args_has(args, 'p')) {
c = cmdq->client; c = item->client;
if (c == NULL || if (c == NULL ||
(c->session != NULL && !(c->flags & CLIENT_CONTROL))) { (c->session != NULL && !(c->flags & CLIENT_CONTROL))) {
cmdq_error(cmdq, "can't write to stdout"); cmdq_error(item, "can't write to stdout");
free(buf); free(buf);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -212,7 +231,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq)
bufname = args_get(args, 'b'); bufname = args_get(args, 'b');
if (paste_set(buf, len, bufname, &cause) != 0) { if (paste_set(buf, len, bufname, &cause) != 0) {
cmdq_error(cmdq, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
free(buf); free(buf);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);

View File

@@ -1,100 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Enter choice mode to choose a buffer.
*/
#define CHOOSE_BUFFER_TEMPLATE \
"#{buffer_name}: #{buffer_size} bytes: #{buffer_sample}"
enum cmd_retval cmd_choose_buffer_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer",
.alias = NULL,
.args = { "F:t:", 0, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_choose_buffer_exec
};
enum cmd_retval
cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c = cmdq->state.c;
struct winlink *wl = cmdq->state.tflag.wl;
struct window_choose_data *cdata;
struct paste_buffer *pb;
char *action, *action_data;
const char *template;
u_int idx;
if (c == NULL) {
cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
if ((template = args_get(args, 'F')) == NULL)
template = CHOOSE_BUFFER_TEMPLATE;
if (paste_get_top(NULL) == NULL)
return (CMD_RETURN_NORMAL);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (CMD_RETURN_NORMAL);
if (args->argc != 0)
action = xstrdup(args->argv[0]);
else
action = xstrdup("paste-buffer -b '%%'");
idx = 0;
pb = NULL;
while ((pb = paste_walk(pb)) != NULL) {
cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = idx;
cdata->ft_template = xstrdup(template);
format_defaults_paste_buffer(cdata->ft, pb);
xasprintf(&action_data, "%s", paste_buffer_name(pb));
cdata->command = cmd_template_replace(action, action_data, 1);
free(action_data);
window_choose_add(wl->window->active, cdata);
idx++;
}
free(action);
window_choose_ready(wl->window->active, 0, NULL);
return (CMD_RETURN_NORMAL);
}

View File

@@ -1,134 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Enter choice mode to choose a client.
*/
#define CHOOSE_CLIENT_TEMPLATE \
"#{client_tty}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}]" \
"#{?client_utf8, (utf8),}#{?client_readonly, (ro),} " \
"(last used #{t:client_activity})"
enum cmd_retval cmd_choose_client_exec(struct cmd *, struct cmd_q *);
void cmd_choose_client_callback(struct window_choose_data *);
const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client",
.alias = NULL,
.args = { "F:t:", 0, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_choose_client_exec
};
struct cmd_choose_client_data {
struct client *client;
};
enum cmd_retval
cmd_choose_client_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c = cmdq->state.c;
struct client *c1;
struct window_choose_data *cdata;
struct winlink *wl = cmdq->state.tflag.wl;
const char *template;
char *action;
u_int idx, cur;
if (c == NULL) {
cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (CMD_RETURN_NORMAL);
if ((template = args_get(args, 'F')) == NULL)
template = CHOOSE_CLIENT_TEMPLATE;
if (args->argc != 0)
action = xstrdup(args->argv[0]);
else
action = xstrdup("detach-client -t '%%'");
cur = idx = 0;
TAILQ_FOREACH(c1, &clients, entry) {
if (c1->session == NULL || c1->tty.path == NULL)
continue;
if (c1 == cmdq->client)
cur = idx;
cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = idx;
cdata->ft_template = xstrdup(template);
format_add(cdata->ft, "line", "%u", idx);
format_defaults(cdata->ft, c1, NULL, NULL, NULL);
cdata->command = cmd_template_replace(action, c1->tty.path, 1);
window_choose_add(wl->window->active, cdata);
idx++;
}
free(action);
window_choose_ready(wl->window->active, cur,
cmd_choose_client_callback);
return (CMD_RETURN_NORMAL);
}
void
cmd_choose_client_callback(struct window_choose_data *cdata)
{
struct client *c;
u_int idx;
if (cdata == NULL)
return;
if (cdata->start_client->flags & CLIENT_DEAD)
return;
idx = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (idx == cdata->idx)
break;
idx++;
}
if (c == NULL || c->session == NULL)
return;
window_choose_data_run(cdata);
}

View File

@@ -18,236 +18,74 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h" #include "tmux.h"
#define CMD_CHOOSE_TREE_WINDOW_ACTION "select-window -t '%%'"
#define CMD_CHOOSE_TREE_SESSION_ACTION "switch-client -t '%%'"
/* /*
* Enter choice mode to choose a session and/or window. * Enter a mode.
*/ */
#define CHOOSE_TREE_SESSION_TEMPLATE \ static enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmdq_item *);
"#{session_name}: #{session_windows} windows" \
"#{?session_grouped, (group ,}" \
"#{session_group}#{?session_grouped,),}" \
"#{?session_attached, (attached),}"
#define CHOOSE_TREE_WINDOW_TEMPLATE \
"#{window_index}: #{window_name}#{window_flags} " \
"\"#{pane_title}\""
enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_choose_tree_entry = { const struct cmd_entry cmd_choose_tree_entry = {
.name = "choose-tree", .name = "choose-tree",
.alias = NULL, .alias = NULL,
.args = { "S:W:swub:c:t:", 0, 1 }, .args = { "F:Gf:NO:st:wZ", 0, 1 },
.usage = "[-suw] [-b session-template] [-c window template] " .usage = "[-GNsw] [-F format] [-f filter] [-O sort-order] "
"[-S format] [-W format] " CMD_TARGET_WINDOW_USAGE, CMD_TARGET_PANE_USAGE " [template]",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_choose_tree_exec .exec = cmd_choose_tree_exec
}; };
const struct cmd_entry cmd_choose_session_entry = { const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-session", .name = "choose-client",
.alias = NULL, .alias = NULL,
.args = { "F:t:", 0, 1 }, .args = { "F:f:NO:t:Z", 0, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]", .usage = "[-N] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_choose_tree_exec .exec = cmd_choose_tree_exec
}; };
const struct cmd_entry cmd_choose_window_entry = { const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-window", .name = "choose-buffer",
.alias = NULL, .alias = NULL,
.args = { "F:t:", 0, 1 }, .args = { "F:f:NO:t:Z", 0, 1 },
.usage = CMD_TARGET_WINDOW_USAGE "[-F format] [template]", .usage = "[-N] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_choose_tree_exec .exec = cmd_choose_tree_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmd_q *cmdq) cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmdq->state.c; struct window_pane *wp = item->target.wp;
struct winlink *wl = cmdq->state.tflag.wl, *wm; const struct window_mode *mode;
struct session *s = cmdq->state.tflag.s, *s2;
struct window_choose_data *wcd = NULL;
const char *ses_template, *win_template;
char *final_win_action, *cur_win_template;
char *final_win_template_middle;
char *final_win_template_last;
const char *ses_action, *win_action;
u_int cur_win, idx_ses, win_ses, win_max;
u_int wflag, sflag;
ses_template = win_template = NULL; if (self->entry == &cmd_choose_buffer_entry) {
ses_action = win_action = NULL; if (paste_get_top(NULL) == NULL)
return (CMD_RETURN_NORMAL);
if (c == NULL) { mode = &window_buffer_mode;
cmdq_error(cmdq, "no client available"); } else if (self->entry == &cmd_choose_client_entry) {
return (CMD_RETURN_ERROR); if (server_client_how_many() == 0)
} return (CMD_RETURN_NORMAL);
mode = &window_client_mode;
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (CMD_RETURN_NORMAL);
/* Sort out which command this is. */
wflag = sflag = 0;
if (self->entry == &cmd_choose_session_entry) {
sflag = 1;
if ((ses_template = args_get(args, 'F')) == NULL)
ses_template = CHOOSE_TREE_SESSION_TEMPLATE;
if (args->argc != 0)
ses_action = args->argv[0];
else
ses_action = CMD_CHOOSE_TREE_SESSION_ACTION;
} else if (self->entry == &cmd_choose_window_entry) {
wflag = 1;
if ((win_template = args_get(args, 'F')) == NULL)
win_template = CHOOSE_TREE_WINDOW_TEMPLATE;
if (args->argc != 0)
win_action = args->argv[0];
else
win_action = CMD_CHOOSE_TREE_WINDOW_ACTION;
} else {
wflag = args_has(args, 'w');
sflag = args_has(args, 's');
if ((ses_action = args_get(args, 'b')) == NULL)
ses_action = CMD_CHOOSE_TREE_SESSION_ACTION;
if ((win_action = args_get(args, 'c')) == NULL)
win_action = CMD_CHOOSE_TREE_WINDOW_ACTION;
if ((ses_template = args_get(args, 'S')) == NULL)
ses_template = CHOOSE_TREE_SESSION_TEMPLATE;
if ((win_template = args_get(args, 'W')) == NULL)
win_template = CHOOSE_TREE_WINDOW_TEMPLATE;
}
/*
* If not asking for windows and sessions, assume no "-ws" given and
* hence display the entire tree outright.
*/
if (!wflag && !sflag)
wflag = sflag = 1;
/*
* If we're drawing in tree mode, including sessions, then pad the
* window template, otherwise just render the windows as a flat list
* without any padding.
*/
if (wflag && sflag) {
xasprintf(&final_win_template_middle,
" \001tq\001> %s", win_template);
xasprintf(&final_win_template_last,
" \001mq\001> %s", win_template);
} else if (wflag) {
final_win_template_middle = xstrdup(win_template);
final_win_template_last = xstrdup(win_template);
} else } else
final_win_template_middle = final_win_template_last = NULL; mode = &window_tree_mode;
idx_ses = cur_win = -1;
RB_FOREACH(s2, sessions, &sessions) {
idx_ses++;
/*
* If we're just choosing windows, jump straight there. Note
* that this implies the current session, so only choose
* windows when the session matches this one.
*/
if (wflag && !sflag) {
if (s != s2)
continue;
goto windows_only;
}
wcd = window_choose_add_session(wl->window->active,
c, s2, ses_template, ses_action, idx_ses);
/* If we're just choosing sessions, skip choosing windows. */
if (sflag && !wflag) {
if (s == s2)
cur_win = idx_ses;
continue;
}
windows_only:
win_ses = win_max = -1;
RB_FOREACH(wm, winlinks, &s2->windows)
win_max++;
RB_FOREACH(wm, winlinks, &s2->windows) {
win_ses++;
if (sflag && wflag)
idx_ses++;
if (wm == s2->curw && s == s2) {
if (wflag && !sflag) {
/*
* Then we're only counting windows.
* So remember which is the current
* window in the list.
*/
cur_win = win_ses;
} else
cur_win = idx_ses;
}
xasprintf(&final_win_action, "%s %s %s",
wcd != NULL ? wcd->command : "",
wcd != NULL ? ";" : "", win_action);
if (win_ses != win_max)
cur_win_template = final_win_template_middle;
else
cur_win_template = final_win_template_last;
window_choose_add_window(wl->window->active,
c, s2, wm, cur_win_template,
final_win_action,
(wflag && !sflag) ? win_ses : idx_ses);
free(final_win_action);
}
/*
* If we're just drawing windows, don't consider moving on to
* other sessions as we only list windows in this session.
*/
if (wflag && !sflag)
break;
}
free(final_win_template_middle);
free(final_win_template_last);
window_choose_ready(wl->window->active, cur_win, NULL);
if (args_has(args, 'u')) {
window_choose_expand_all(wl->window->active);
window_choose_set_current(wl->window->active, cur_win);
}
window_pane_set_mode(wp, mode, &item->target, args);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -29,56 +29,64 @@
* Prompt for command in client. * Prompt for command in client.
*/ */
enum cmd_retval cmd_command_prompt_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_command_prompt_exec(struct cmd *,
struct cmdq_item *);
int cmd_command_prompt_callback(void *, const char *); static int cmd_command_prompt_callback(struct client *, void *,
void cmd_command_prompt_free(void *); const char *, int);
static void cmd_command_prompt_free(void *);
const struct cmd_entry cmd_command_prompt_entry = { const struct cmd_entry cmd_command_prompt_entry = {
.name = "command-prompt", .name = "command-prompt",
.alias = NULL, .alias = NULL,
.args = { "I:p:t:", 0, 1 }, .args = { "1iI:Np:t:", 0, 1 },
.usage = "[-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " " .usage = "[-1Ni] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
"[template]", "[template]",
.tflag = CMD_CLIENT,
.flags = 0, .flags = 0,
.exec = cmd_command_prompt_exec .exec = cmd_command_prompt_exec
}; };
struct cmd_command_prompt_cdata { struct cmd_command_prompt_cdata {
struct client *c; int flags;
char *inputs;
char *next_input; char *inputs;
char *next_prompt; char *next_input;
char *prompts;
char *template; char *prompts;
int idx; char *next_prompt;
char *template;
int idx;
}; };
enum cmd_retval static enum cmd_retval
cmd_command_prompt_exec(struct cmd *self, struct cmd_q *cmdq) cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
const char *inputs, *prompts; const char *inputs, *prompts;
struct cmd_command_prompt_cdata *cdata; struct cmd_command_prompt_cdata *cdata;
struct client *c = cmdq->state.c; struct client *c;
char *prompt, *ptr, *input = NULL; char *prompt, *ptr, *input = NULL;
size_t n; size_t n;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (c->prompt_string != NULL) if (c->prompt_string != NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
cdata = xmalloc(sizeof *cdata); cdata = xcalloc(1, sizeof *cdata);
cdata->c = c;
cdata->idx = 1;
cdata->inputs = NULL; cdata->inputs = NULL;
cdata->next_input = NULL; cdata->next_input = NULL;
cdata->next_prompt = NULL;
cdata->prompts = NULL; cdata->prompts = NULL;
cdata->next_prompt = NULL;
cdata->template = NULL; cdata->template = NULL;
cdata->idx = 1;
if (args->argc != 0) if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]); cdata->template = xstrdup(args->argv[0]);
@@ -108,34 +116,45 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_q *cmdq)
input = strsep(&cdata->next_input, ","); input = strsep(&cdata->next_input, ",");
} }
if (args_has(args, '1'))
cdata->flags |= PROMPT_SINGLE;
else if (args_has(args, 'N'))
cdata->flags |= PROMPT_NUMERIC;
else if (args_has(args, 'i'))
cdata->flags |= PROMPT_INCREMENTAL;
status_prompt_set(c, prompt, input, cmd_command_prompt_callback, status_prompt_set(c, prompt, input, cmd_command_prompt_callback,
cmd_command_prompt_free, cdata, 0); cmd_command_prompt_free, cdata, cdata->flags);
free(prompt); free(prompt);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
int static int
cmd_command_prompt_callback(void *data, const char *s) cmd_command_prompt_callback(struct client *c, void *data, const char *s,
int done)
{ {
struct cmd_command_prompt_cdata *cdata = data; struct cmd_command_prompt_cdata *cdata = data;
struct client *c = cdata->c; struct cmdq_item *new_item;
struct cmd_list *cmdlist; char *new_template, *prompt, *ptr;
char *cause, *new_template, *prompt, *ptr;
char *input = NULL; char *input = NULL;
struct cmd_parse_result *pr;
if (s == NULL) if (s == NULL)
return (0); return (0);
if (done && (cdata->flags & PROMPT_INCREMENTAL))
return (0);
new_template = cmd_template_replace(cdata->template, s, cdata->idx); new_template = cmd_template_replace(cdata->template, s, cdata->idx);
free(cdata->template); if (done) {
cdata->template = new_template; free(cdata->template);
cdata->template = new_template;
}
/* /*
* Check if there are more prompts; if so, get its respective input * Check if there are more prompts; if so, get its respective input
* and update the prompt data. * and update the prompt data.
*/ */
if ((ptr = strsep(&cdata->next_prompt, ",")) != NULL) { if (done && (ptr = strsep(&cdata->next_prompt, ",")) != NULL) {
xasprintf(&prompt, "%s ", ptr); xasprintf(&prompt, "%s ", ptr);
input = strsep(&cdata->next_input, ","); input = strsep(&cdata->next_input, ",");
status_prompt_update(c, prompt, input); status_prompt_update(c, prompt, input);
@@ -145,24 +164,31 @@ cmd_command_prompt_callback(void *data, const char *s)
return (1); return (1);
} }
if (cmd_string_parse(new_template, &cmdlist, NULL, 0, &cause) != 0) { pr = cmd_parse_from_string(new_template, NULL);
if (cause != NULL) { switch (pr->status) {
*cause = toupper((u_char) *cause); case CMD_PARSE_EMPTY:
status_message_set(c, "%s", cause); new_item = NULL;
free(cause); break;
} case CMD_PARSE_ERROR:
return (0); new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item);
break;
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
cmd_list_free(pr->cmdlist);
cmdq_append(c, new_item);
break;
} }
cmdq_run(c->cmdq, cmdlist, NULL); if (!done)
cmd_list_free(cmdlist); free(new_template);
if (c->prompt_inputcb != cmd_command_prompt_callback)
if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback)
return (1); return (1);
return (0); return (0);
} }
void static void
cmd_command_prompt_free(void *data) cmd_command_prompt_free(void *data)
{ {
struct cmd_command_prompt_cdata *cdata = data; struct cmd_command_prompt_cdata *cdata = data;

View File

@@ -28,10 +28,12 @@
* Asks for confirmation before executing a command. * Asks for confirmation before executing a command.
*/ */
enum cmd_retval cmd_confirm_before_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_confirm_before_exec(struct cmd *,
struct cmdq_item *);
int cmd_confirm_before_callback(void *, const char *); static int cmd_confirm_before_callback(struct client *, void *,
void cmd_confirm_before_free(void *); const char *, int);
static void cmd_confirm_before_free(void *);
const struct cmd_entry cmd_confirm_before_entry = { const struct cmd_entry cmd_confirm_before_entry = {
.name = "confirm-before", .name = "confirm-before",
@@ -40,26 +42,26 @@ const struct cmd_entry cmd_confirm_before_entry = {
.args = { "p:t:", 1, 1 }, .args = { "p:t:", 1, 1 },
.usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command", .usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
.tflag = CMD_CLIENT,
.flags = 0, .flags = 0,
.exec = cmd_confirm_before_exec .exec = cmd_confirm_before_exec
}; };
struct cmd_confirm_before_data { struct cmd_confirm_before_data {
char *cmd; char *cmd;
struct client *client;
}; };
enum cmd_retval static enum cmd_retval
cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq) cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_confirm_before_data *cdata; struct cmd_confirm_before_data *cdata;
struct client *c = cmdq->state.c; struct client *c;
char *cmd, *copy, *new_prompt, *ptr; char *cmd, *copy, *new_prompt, *ptr;
const char *prompt; const char *prompt;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if ((prompt = args_get(args, 'p')) != NULL) if ((prompt = args_get(args, 'p')) != NULL)
xasprintf(&new_prompt, "%s ", prompt); xasprintf(&new_prompt, "%s ", prompt);
else { else {
@@ -72,9 +74,6 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq)
cdata = xmalloc(sizeof *cdata); cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[0]); cdata->cmd = xstrdup(args->argv[0]);
cdata->client = c;
cdata->client->references++;
status_prompt_set(c, new_prompt, NULL, status_prompt_set(c, new_prompt, NULL,
cmd_confirm_before_callback, cmd_confirm_before_free, cdata, cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
PROMPT_SINGLE); PROMPT_SINGLE);
@@ -83,43 +82,46 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
int static int
cmd_confirm_before_callback(void *data, const char *s) cmd_confirm_before_callback(struct client *c, void *data, const char *s,
__unused int done)
{ {
struct cmd_confirm_before_data *cdata = data; struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client; struct cmdq_item *new_item;
struct cmd_list *cmdlist; struct cmd_parse_result *pr;
char *cause;
if (c->flags & CLIENT_DEAD) if (c->flags & CLIENT_DEAD)
return (0); return (0);
if (s == NULL || *s == '\0') if (s == NULL || *s == '\0')
return (0); return (0);
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0') if (tolower((u_char)s[0]) != 'y' || s[1] != '\0')
return (0); return (0);
if (cmd_string_parse(cdata->cmd, &cmdlist, NULL, 0, &cause) != 0) { pr = cmd_parse_from_string(cdata->cmd, NULL);
if (cause != NULL) { switch (pr->status) {
cmdq_error(c->cmdq, "%s", cause); case CMD_PARSE_EMPTY:
free(cause); new_item = NULL;
} break;
return (0); case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item);
break;
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
cmd_list_free(pr->cmdlist);
cmdq_append(c, new_item);
break;
} }
cmdq_run(c->cmdq, cmdlist, NULL);
cmd_list_free(cmdlist);
return (0); return (0);
} }
void static void
cmd_confirm_before_free(void *data) cmd_confirm_before_free(void *data)
{ {
struct cmd_confirm_before_data *cdata = data; struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client;
server_client_unref(c);
free(cdata->cmd); free(cdata->cmd);
free(cdata); free(cdata);

View File

@@ -24,7 +24,7 @@
* Enter copy or clock mode. * Enter copy or clock mode.
*/ */
enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_copy_mode_entry = { const struct cmd_entry cmd_copy_mode_entry = {
.name = "copy-mode", .name = "copy-mode",
@@ -33,9 +33,9 @@ const struct cmd_entry cmd_copy_mode_entry = {
.args = { "Met:u", 0, 0 }, .args = { "Met:u", 0, 0 },
.usage = "[-Mu] " CMD_TARGET_PANE_USAGE, .usage = "[-Mu] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_copy_mode_exec .exec = cmd_copy_mode_exec
}; };
@@ -46,43 +46,38 @@ const struct cmd_entry cmd_clock_mode_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE, .usage = CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_copy_mode_exec .exec = cmd_copy_mode_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq) cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmdq->client; struct cmdq_shared *shared = item->shared;
struct client *c = item->client;
struct session *s; struct session *s;
struct window_pane *wp = cmdq->state.tflag.wp; struct window_pane *wp = item->target.wp;
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
if ((wp = cmd_mouse_pane(&cmdq->item->mouse, &s, NULL)) == NULL) if ((wp = cmd_mouse_pane(&shared->mouse, &s, NULL)) == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s) if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (self->entry == &cmd_clock_mode_entry) { if (self->entry == &cmd_clock_mode_entry) {
window_pane_set_mode(wp, &window_clock_mode); window_pane_set_mode(wp, &window_clock_mode, NULL, NULL);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (wp->mode != &window_copy_mode) { if (!window_pane_set_mode(wp, &window_copy_mode, NULL, args)) {
if (window_pane_set_mode(wp, &window_copy_mode) != 0) if (args_has(args, 'M'))
return (CMD_RETURN_NORMAL); window_copy_start_drag(c, &shared->mouse);
window_copy_init_from_pane(wp, args_has(self->args, 'e'));
} }
if (args_has(args, 'M')) { if (args_has(self->args, 'u'))
if (wp->mode != NULL && wp->mode != &window_copy_mode)
return (CMD_RETURN_NORMAL);
window_copy_start_drag(c, &cmdq->item->mouse);
}
if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
window_copy_pageup(wp, 0); window_copy_pageup(wp, 0);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -26,17 +26,18 @@
* Detach a client. * Detach a client.
*/ */
enum cmd_retval cmd_detach_client_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_detach_client_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_detach_client_entry = { const struct cmd_entry cmd_detach_client_entry = {
.name = "detach-client", .name = "detach-client",
.alias = "detach", .alias = "detach",
.args = { "as:t:P", 0, 0 }, .args = { "aE:s:t:P", 0, 0 },
.usage = "[-P] [-a] [-s target-session] " CMD_TARGET_CLIENT_USAGE, .usage = "[-aP] [-E shell-command] "
"[-s target-session] " CMD_TARGET_CLIENT_USAGE,
.sflag = CMD_SESSION, .source = { 's', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.tflag = CMD_CLIENT,
.flags = CMD_READONLY, .flags = CMD_READONLY,
.exec = cmd_detach_client_exec .exec = cmd_detach_client_exec
@@ -49,24 +50,24 @@ const struct cmd_entry cmd_suspend_client_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE, .usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = 0, .flags = 0,
.exec = cmd_detach_client_exec .exec = cmd_detach_client_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq) cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmdq->state.c, *cloop; struct client *c, *cloop;
struct session *s; struct session *s;
enum msgtype msgtype; enum msgtype msgtype;
const char *cmd = args_get(args, 'E');
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (self->entry == &cmd_suspend_client_entry) { if (self->entry == &cmd_suspend_client_entry) {
tty_stop_tty(&c->tty); server_client_suspend(c);
c->flags |= CLIENT_SUSPENDED;
proc_send(c->peer, MSG_SUSPEND, -1, NULL, 0);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -76,22 +77,35 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq)
msgtype = MSG_DETACH; msgtype = MSG_DETACH;
if (args_has(args, 's')) { if (args_has(args, 's')) {
s = cmdq->state.sflag.s; s = item->source.s;
if (s == NULL)
return (CMD_RETURN_NORMAL);
TAILQ_FOREACH(cloop, &clients, entry) { TAILQ_FOREACH(cloop, &clients, entry) {
if (cloop->session == s) if (cloop->session == s) {
server_client_detach(cloop, msgtype); if (cmd != NULL)
server_client_exec(cloop, cmd);
else
server_client_detach(cloop, msgtype);
}
} }
return (CMD_RETURN_STOP); return (CMD_RETURN_STOP);
} }
if (args_has(args, 'a')) { if (args_has(args, 'a')) {
TAILQ_FOREACH(cloop, &clients, entry) { TAILQ_FOREACH(cloop, &clients, entry) {
if (cloop->session != NULL && cloop != c) if (cloop->session != NULL && cloop != c) {
server_client_detach(cloop, msgtype); if (cmd != NULL)
server_client_exec(cloop, cmd);
else
server_client_detach(cloop, msgtype);
}
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
server_client_detach(c, msgtype); if (cmd != NULL)
server_client_exec(c, cmd);
else
server_client_detach(c, msgtype);
return (CMD_RETURN_STOP); return (CMD_RETURN_STOP);
} }

178
cmd-display-menu.c Normal file
View File

@@ -0,0 +1,178 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Display a menu on a client.
*/
static enum cmd_retval cmd_display_menu_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_display_menu_entry = {
.name = "display-menu",
.alias = "menu",
.args = { "c:t:T:x:y:", 1, -1 },
.usage = "[-c target-client] " CMD_TARGET_PANE_USAGE " [-T title] "
"[-x position] [-y position] name key command ...",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_display_menu_exec
};
static enum cmd_retval
cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
struct cmd_find_state *fs = &item->target;
struct menu *menu = NULL;
struct style_range *sr;
struct menu_item menu_item;
const char *xp, *yp, *key;
char *title, *name;
int at, flags, i;
u_int px, py, ox, oy, sx, sy;
if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (c->overlay_draw != NULL)
return (CMD_RETURN_NORMAL);
at = status_at_line(c);
if (args_has(args, 'T'))
title = format_single(NULL, args_get(args, 'T'), c, s, wl, wp);
else
title = xstrdup("");
menu = menu_create(title);
for (i = 0; i != args->argc; /* nothing */) {
name = args->argv[i++];
if (*name == '\0') {
menu_add_item(menu, NULL, item, c, fs);
continue;
}
if (args->argc - i < 2) {
cmdq_error(item, "not enough arguments");
free(title);
menu_free(menu);
return (CMD_RETURN_ERROR);
}
key = args->argv[i++];
menu_item.name = name;
menu_item.key = key_string_lookup_string(key);
menu_item.command = args->argv[i++];
menu_add_item(menu, &menu_item, item, c, fs);
}
free(title);
if (menu == NULL) {
cmdq_error(item, "invalid menu arguments");
return (CMD_RETURN_ERROR);
}
if (menu->count == 0) {
menu_free(menu);
return (CMD_RETURN_NORMAL);
}
xp = args_get(args, 'x');
if (xp == NULL)
px = 0;
else if (strcmp(xp, "R") == 0)
px = c->tty.sx - 1;
else if (strcmp(xp, "P") == 0) {
tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
if (wp->xoff >= ox)
px = wp->xoff - ox;
else
px = 0;
} else if (strcmp(xp, "M") == 0 && item->shared->mouse.valid) {
if (item->shared->mouse.x > (menu->width + 4) / 2)
px = item->shared->mouse.x - (menu->width + 4) / 2;
else
px = 0;
}
else if (strcmp(xp, "W") == 0) {
if (at == -1)
px = 0;
else {
TAILQ_FOREACH(sr, &c->status.entries[0].ranges, entry) {
if (sr->type != STYLE_RANGE_WINDOW)
continue;
if (sr->argument == (u_int)wl->idx)
break;
}
if (sr != NULL)
px = sr->start;
else
px = 0;
}
} else
px = strtoul(xp, NULL, 10);
if (px + menu->width + 4 >= c->tty.sx)
px = c->tty.sx - menu->width - 4;
yp = args_get(args, 'y');
if (yp == NULL)
py = 0;
else if (strcmp(yp, "P") == 0) {
tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
if (wp->yoff + wp->sy >= oy)
py = wp->yoff + wp->sy - oy;
else
py = 0;
} else if (strcmp(yp, "M") == 0 && item->shared->mouse.valid)
py = item->shared->mouse.y + menu->count + 2;
else if (strcmp(yp, "S") == 0) {
if (at == -1)
py = c->tty.sy;
else if (at == 0)
py = status_line_size(c) + menu->count + 2;
else
py = at;
} else
py = strtoul(yp, NULL, 10);
if (py < menu->count + 2)
py = 0;
else
py -= menu->count + 2;
if (py + menu->count + 2 >= c->tty.sy)
py = c->tty.sy - menu->count - 2;
flags = 0;
if (!item->shared->mouse.valid)
flags |= MENU_NOMOUSE;
if (menu_display(menu, flags, item, px, py, c, fs, NULL, NULL) != 0)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}

View File

@@ -32,37 +32,55 @@
"#{window_name}, current pane #{pane_index} " \ "#{window_name}, current pane #{pane_index} " \
"- (%H:%M %d-%b-%y)" "- (%H:%M %d-%b-%y)"
enum cmd_retval cmd_display_message_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_display_message_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_display_message_entry = { const struct cmd_entry cmd_display_message_entry = {
.name = "display-message", .name = "display-message",
.alias = "display", .alias = "display",
.args = { "c:pt:F:", 0, 1 }, .args = { "ac:Ipt:F:v", 0, 1 },
.usage = "[-p] [-c target-client] [-F format] " .usage = "[-aIpv] [-c target-client] [-F format] "
CMD_TARGET_PANE_USAGE " [message]", CMD_TARGET_PANE_USAGE " [message]",
.cflag = CMD_CLIENT_CANFAIL, .target = { 't', CMD_FIND_PANE, 0 },
.tflag = CMD_PANE,
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_display_message_exec .exec = cmd_display_message_exec
}; };
enum cmd_retval static void
cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq) cmd_display_message_each(const char *key, const char *value, void *arg)
{
struct cmdq_item *item = arg;
cmdq_print(item, "%s=%s", key, value);
}
static enum cmd_retval
cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmdq->state.c; struct client *c, *target_c;
struct session *s = cmdq->state.tflag.s; struct session *s = item->target.s;
struct winlink *wl = cmdq->state.tflag.wl; struct winlink *wl = item->target.wl;
struct window_pane *wp = cmdq->state.tflag.wp; struct window_pane *wp = item->target.wp;
const char *template; const char *template;
char *msg; char *msg, *cause;
struct format_tree *ft; struct format_tree *ft;
int flags;
if (args_has(args, 'I')) {
if (window_pane_start_input(wp, item, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_WAIT);
}
if (args_has(args, 'F') && args->argc != 0) { if (args_has(args, 'F') && args->argc != 0) {
cmdq_error(cmdq, "only one of -F or argument must be given"); cmdq_error(item, "only one of -F or argument must be given");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -72,12 +90,32 @@ cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq)
if (template == NULL) if (template == NULL)
template = DISPLAY_MESSAGE_TEMPLATE; template = DISPLAY_MESSAGE_TEMPLATE;
ft = format_create(cmdq, 0); /*
format_defaults(ft, c, s, wl, wp); * -c is intended to be the client where the message should be
* displayed if -p is not given. But it makes sense to use it for the
* formats too, assuming it matches the session. If it doesn't, use the
* best client for the session.
*/
c = cmd_find_client(item, args_get(args, 'c'), 1);
if (c != NULL && c->session == s)
target_c = c;
else
target_c = cmd_find_best_client(s);
if (args_has(self->args, 'v'))
flags = FORMAT_VERBOSE;
else
flags = 0;
ft = format_create(item->client, item, FORMAT_NONE, flags);
format_defaults(ft, target_c, s, wl, wp);
msg = format_expand_time(ft, template, time(NULL)); if (args_has(args, 'a')) {
format_each(ft, cmd_display_message_each, item);
return (CMD_RETURN_NORMAL);
}
msg = format_expand_time(ft, template);
if (args_has(self->args, 'p')) if (args_has(self->args, 'p'))
cmdq_print(cmdq, "%s", msg); cmdq_print(item, "%s", msg);
else if (c != NULL) else if (c != NULL)
status_message_set(c, "%s", msg); status_message_set(c, "%s", msg);
free(msg); free(msg);

View File

@@ -18,8 +18,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -27,71 +27,256 @@
* Display panes on a client. * Display panes on a client.
*/ */
static enum cmd_retval cmd_display_panes_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_display_panes_exec(struct cmd *,
struct cmdq_item *);
static void cmd_display_panes_callback(struct client *,
struct window_pane *);
const struct cmd_entry cmd_display_panes_entry = { const struct cmd_entry cmd_display_panes_entry = {
.name = "display-panes", .name = "display-panes",
.alias = "displayp", .alias = "displayp",
.args = { "t:", 0, 1 }, .args = { "bd:t:", 0, 1 },
.usage = CMD_TARGET_CLIENT_USAGE, .usage = "[-b] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
.tflag = CMD_CLIENT, .flags = CMD_AFTERHOOK,
.flags = 0,
.exec = cmd_display_panes_exec .exec = cmd_display_panes_exec
}; };
static enum cmd_retval struct cmd_display_panes_data {
cmd_display_panes_exec(struct cmd *self, struct cmd_q *cmdq) struct cmdq_item *item;
char *command;
};
static void
cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
struct window_pane *wp)
{ {
struct args *args = self->args; struct client *c = ctx->c;
struct client *c = cmdq->state.c; struct tty *tty = &c->tty;
struct session *s = c->session;
struct options *oo = s->options;
struct window *w = wp->window;
struct grid_cell gc;
u_int idx, px, py, i, j, xoff, yoff, sx, sy;
int colour, active_colour;
char buf[16], *ptr;
size_t len;
if (c->identify_callback != NULL) if (wp->xoff + wp->sx <= ctx->ox ||
return (CMD_RETURN_NORMAL); wp->xoff >= ctx->ox + ctx->sx ||
wp->yoff + wp->sy <= ctx->oy ||
wp->yoff >= ctx->oy + ctx->sy)
return;
c->identify_callback = cmd_display_panes_callback; if (wp->xoff >= ctx->ox && wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
if (args->argc != 0) /* All visible. */
c->identify_callback_data = xstrdup(args->argv[0]); xoff = wp->xoff - ctx->ox;
sx = wp->sx;
} else if (wp->xoff < ctx->ox &&
wp->xoff + wp->sx > ctx->ox + ctx->sx) {
/* Both left and right not visible. */
xoff = 0;
sx = ctx->sx;
} else if (wp->xoff < ctx->ox) {
/* Left not visible. */
xoff = 0;
sx = wp->sx - (ctx->ox - wp->xoff);
} else {
/* Right not visible. */
xoff = wp->xoff - ctx->ox;
sx = wp->sx - xoff;
}
if (wp->yoff >= ctx->oy && wp->yoff + wp->sy <= ctx->oy + ctx->sy) {
/* All visible. */
yoff = wp->yoff - ctx->oy;
sy = wp->sy;
} else if (wp->yoff < ctx->oy &&
wp->yoff + wp->sy > ctx->oy + ctx->sy) {
/* Both top and bottom not visible. */
yoff = 0;
sy = ctx->sy;
} else if (wp->yoff < ctx->oy) {
/* Top not visible. */
yoff = 0;
sy = wp->sy - (ctx->oy - wp->yoff);
} else {
/* Bottom not visible. */
yoff = wp->yoff - ctx->oy;
sy = wp->sy - yoff;
}
if (ctx->statustop)
yoff += ctx->statuslines;
px = sx / 2;
py = sy / 2;
if (window_pane_index(wp, &idx) != 0)
fatalx("index not found");
len = xsnprintf(buf, sizeof buf, "%u", idx);
if (sx < len)
return;
colour = options_get_number(oo, "display-panes-colour");
active_colour = options_get_number(oo, "display-panes-active-colour");
if (sx < len * 6 || sy < 5) {
tty_cursor(tty, xoff + px - len / 2, yoff + py);
goto draw_text;
}
px -= len * 3;
py -= 2;
memcpy(&gc, &grid_default_cell, sizeof gc);
if (w->active == wp)
gc.bg = active_colour;
else else
c->identify_callback_data = xstrdup("select-pane -t '%%'"); gc.bg = colour;
gc.flags |= GRID_FLAG_NOPALETTE;
server_set_identify(c); tty_attributes(tty, &gc, wp);
for (ptr = buf; *ptr != '\0'; ptr++) {
if (*ptr < '0' || *ptr > '9')
continue;
idx = *ptr - '0';
return (CMD_RETURN_NORMAL); for (j = 0; j < 5; j++) {
for (i = px; i < px + 5; i++) {
tty_cursor(tty, xoff + i, yoff + py + j);
if (window_clock_table[idx][j][i - px])
tty_putc(tty, ' ');
}
}
px += 6;
}
len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy);
if (sx < len || sy < 6)
return;
tty_cursor(tty, xoff + sx - len, yoff);
draw_text:
memcpy(&gc, &grid_default_cell, sizeof gc);
if (w->active == wp)
gc.fg = active_colour;
else
gc.fg = colour;
gc.flags |= GRID_FLAG_NOPALETTE;
tty_attributes(tty, &gc, wp);
tty_puts(tty, buf);
tty_cursor(tty, 0, 0);
} }
static void static void
cmd_display_panes_callback(struct client *c, struct window_pane *wp) cmd_display_panes_draw(struct client *c, struct screen_redraw_ctx *ctx)
{ {
struct cmd_list *cmdlist; struct window *w = c->session->curw->window;
char *template, *cmd, *expanded, *cause; struct window_pane *wp;
template = c->identify_callback_data; log_debug("%s: %s @%u", __func__, c->name, w->id);
if (wp != NULL) {
xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(template, expanded, 1);
if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (cause != NULL) { if (window_pane_visible(wp))
*cause = toupper((u_char) *cause); cmd_display_panes_draw_pane(ctx, wp);
status_message_set(c, "%s", cause); }
free(cause); }
}
} else {
cmdq_run(c->cmdq, cmdlist, NULL);
cmd_list_free(cmdlist);
}
free(cmd); static void
free(expanded); cmd_display_panes_free(struct client *c)
{
struct cmd_display_panes_data *cdata = c->overlay_data;
if (cdata->item != NULL)
cmdq_continue(cdata->item);
free(cdata->command);
free(cdata);
}
static int
cmd_display_panes_key(struct client *c, struct key_event *event)
{
struct cmd_display_panes_data *cdata = c->overlay_data;
struct cmdq_item *new_item;
char *cmd, *expanded;
struct window *w = c->session->curw->window;
struct window_pane *wp;
struct cmd_parse_result *pr;
if (event->key < '0' || event->key > '9')
return (-1);
wp = window_pane_at_index(w, event->key - '0');
if (wp == NULL)
return (1);
window_unzoom(w);
xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(cdata->command, expanded, 1);
pr = cmd_parse_from_string(cmd, NULL);
switch (pr->status) {
case CMD_PARSE_EMPTY:
new_item = NULL;
break;
case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item);
break;
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
cmd_list_free(pr->cmdlist);
cmdq_append(c, new_item);
break;
} }
free(c->identify_callback_data); free(cmd);
c->identify_callback_data = NULL; free(expanded);
c->identify_callback = NULL; return (1);
}
static enum cmd_retval
cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
struct session *s;
u_int delay;
char *cause;
struct cmd_display_panes_data *cdata;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
s = c->session;
if (c->overlay_draw != NULL)
return (CMD_RETURN_NORMAL);
if (args_has(args, 'd')) {
delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "delay %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
} else
delay = options_get_number(s->options, "display-panes-time");
cdata = xmalloc(sizeof *cdata);
if (args->argc != 0)
cdata->command = xstrdup(args->argv[0]);
else
cdata->command = xstrdup("select-pane -t '%%'");
if (args_has(args, 'b'))
cdata->item = NULL;
else
cdata->item = item;
server_client_set_overlay(c, delay, cmd_display_panes_draw,
cmd_display_panes_key, cmd_display_panes_free, cdata);
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
} }

View File

@@ -18,9 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -28,213 +26,100 @@
* Find window containing text. * Find window containing text.
*/ */
#define FIND_WINDOW_TEMPLATE \ static enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmdq_item *);
"#{window_index}: #{window_name} " \
"[#{window_width}x#{window_height}] " \
"(#{window_panes} panes) #{window_find_matches}"
enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmd_q *);
void cmd_find_window_callback(struct window_choose_data *);
/* Flags for determining matching behavior. */
#define CMD_FIND_WINDOW_BY_TITLE 0x1
#define CMD_FIND_WINDOW_BY_CONTENT 0x2
#define CMD_FIND_WINDOW_BY_NAME 0x4
#define CMD_FIND_WINDOW_ALL \
(CMD_FIND_WINDOW_BY_TITLE | \
CMD_FIND_WINDOW_BY_CONTENT | \
CMD_FIND_WINDOW_BY_NAME)
const struct cmd_entry cmd_find_window_entry = { const struct cmd_entry cmd_find_window_entry = {
.name = "find-window", .name = "find-window",
.alias = "findw", .alias = "findw",
.args = { "F:CNt:T", 1, 4 }, .args = { "CNrt:TZ", 1, 1 },
.usage = "[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string", .usage = "[-CNrTZ] " CMD_TARGET_PANE_USAGE " match-string",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_find_window_exec .exec = cmd_find_window_exec
}; };
struct cmd_find_window_data { static enum cmd_retval
struct winlink *wl; cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
char *list_ctx;
u_int pane_id;
TAILQ_ENTRY(cmd_find_window_data) entry;
};
TAILQ_HEAD(cmd_find_window_list, cmd_find_window_data);
u_int cmd_find_window_match_flags(struct args *);
void cmd_find_window_match(struct cmd_find_window_list *, int,
struct winlink *, const char *, const char *);
u_int
cmd_find_window_match_flags(struct args *args)
{ {
u_int match_flags = 0; struct args *args = self->args, *new_args;
struct window_pane *wp = item->target.wp;
const char *s = args->argv[0];
char *filter, *argv = { NULL };
int C, N, T;
/* Turn on flags based on the options. */ C = args_has(args, 'C');
if (args_has(args, 'T')) N = args_has(args, 'N');
match_flags |= CMD_FIND_WINDOW_BY_TITLE; T = args_has(args, 'T');
if (args_has(args, 'C'))
match_flags |= CMD_FIND_WINDOW_BY_CONTENT;
if (args_has(args, 'N'))
match_flags |= CMD_FIND_WINDOW_BY_NAME;
/* If none of the flags were set, default to matching anything. */ if (!C && !N && !T)
if (match_flags == 0) C = N = T = 1;
match_flags = CMD_FIND_WINDOW_ALL;
return (match_flags); if (!args_has(args, 'r')) {
} if (C && N && T) {
xasprintf(&filter,
void "#{||:"
cmd_find_window_match(struct cmd_find_window_list *find_list, "#{C:%s},#{||:#{m:*%s*,#{window_name}},"
int match_flags, struct winlink *wl, const char *str, "#{m:*%s*,#{pane_title}}}}",
const char *searchstr) s, s, s);
{ } else if (C && N) {
struct cmd_find_window_data *find_data; xasprintf(&filter,
struct window_pane *wp; "#{||:#{C:%s},#{m:*%s*,#{window_name}}}",
u_int i, line; s, s);
char *sres; } else if (C && T) {
xasprintf(&filter,
find_data = xcalloc(1, sizeof *find_data); "#{||:#{C:%s},#{m:*%s*,#{pane_title}}}",
s, s);
i = 0; } else if (N && T) {
TAILQ_FOREACH(wp, &wl->window->panes, entry) { xasprintf(&filter,
i++; "#{||:#{m:*%s*,#{window_name}},"
"#{m:*%s*,#{pane_title}}}",
if ((match_flags & CMD_FIND_WINDOW_BY_NAME) && s, s);
fnmatch(searchstr, wl->window->name, 0) == 0) { } else if (C)
find_data->list_ctx = xstrdup(""); xasprintf(&filter, "#{C:%s}", s);
break; else if (N)
} xasprintf(&filter, "#{m:*%s*,#{window_name}}", s);
else
if ((match_flags & CMD_FIND_WINDOW_BY_TITLE) && xasprintf(&filter, "#{m:*%s*,#{pane_title}}", s);
fnmatch(searchstr, wp->base.title, 0) == 0) { } else {
xasprintf(&find_data->list_ctx, if (C && N && T) {
"pane %u title: \"%s\"", i - 1, wp->base.title); xasprintf(&filter,
break; "#{||:"
} "#{C/r:%s},#{||:#{m/r:%s,#{window_name}},"
"#{m/r:%s,#{pane_title}}}}",
if (match_flags & CMD_FIND_WINDOW_BY_CONTENT && s, s, s);
(sres = window_pane_search(wp, str, &line)) != NULL) { } else if (C && N) {
xasprintf(&find_data->list_ctx, xasprintf(&filter,
"pane %u line %u: \"%s\"", i - 1, line + 1, sres); "#{||:#{C/r:%s},#{m/r:%s,#{window_name}}}",
free(sres); s, s);
break; } else if (C && T) {
} xasprintf(&filter,
"#{||:#{C/r:%s},#{m/r:%s,#{pane_title}}}",
s, s);
} else if (N && T) {
xasprintf(&filter,
"#{||:#{m/r:%s,#{window_name}},"
"#{m/r:%s,#{pane_title}}}",
s, s);
} else if (C)
xasprintf(&filter, "#{C/r:%s}", s);
else if (N)
xasprintf(&filter, "#{m/r:%s,#{window_name}}", s);
else
xasprintf(&filter, "#{m/r:%s,#{pane_title}}", s);
} }
if (find_data->list_ctx != NULL) { new_args = args_parse("", 1, &argv);
find_data->wl = wl; if (args_has(args, 'Z'))
find_data->pane_id = i - 1; args_set(new_args, 'Z', NULL);
TAILQ_INSERT_TAIL(find_list, find_data, entry); args_set(new_args, 'f', filter);
} else
free(find_data);
}
enum cmd_retval window_pane_set_mode(wp, &window_tree_mode, &item->target, new_args);
cmd_find_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c = cmdq->state.c;
struct window_choose_data *cdata;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl, *wm;
struct cmd_find_window_list find_list;
struct cmd_find_window_data *find_data;
struct cmd_find_window_data *find_data1;
char *str, *searchstr;
const char *template;
u_int i, match_flags;
if (c == NULL) { args_free(new_args);
cmdq_error(cmdq, "no client available"); free(filter);
return (CMD_RETURN_ERROR);
}
if ((template = args_get(args, 'F')) == NULL)
template = FIND_WINDOW_TEMPLATE;
match_flags = cmd_find_window_match_flags(args);
str = args->argv[0];
TAILQ_INIT(&find_list);
xasprintf(&searchstr, "*%s*", str);
RB_FOREACH(wm, winlinks, &s->windows)
cmd_find_window_match(&find_list, match_flags, wm, str, searchstr);
free(searchstr);
if (TAILQ_EMPTY(&find_list)) {
cmdq_error(cmdq, "no windows matching: %s", str);
return (CMD_RETURN_ERROR);
}
if (TAILQ_NEXT(TAILQ_FIRST(&find_list), entry) == NULL) {
if (session_select(s, TAILQ_FIRST(&find_list)->wl->idx) == 0)
server_redraw_session(s);
recalculate_sizes();
goto out;
}
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
goto out;
i = 0;
TAILQ_FOREACH(find_data, &find_list, entry) {
cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = find_data->wl->idx;
cdata->wl = find_data->wl;
cdata->ft_template = xstrdup(template);
cdata->pane_id = find_data->pane_id;
format_add(cdata->ft, "line", "%u", i);
format_add(cdata->ft, "window_find_matches", "%s",
find_data->list_ctx);
format_defaults(cdata->ft, NULL, s, find_data->wl, NULL);
window_choose_add(wl->window->active, cdata);
i++;
}
window_choose_ready(wl->window->active, 0, cmd_find_window_callback);
out:
TAILQ_FOREACH_SAFE(find_data, &find_list, entry, find_data1) {
free(find_data->list_ctx);
TAILQ_REMOVE(&find_list, find_data, entry);
free(find_data);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
void
cmd_find_window_callback(struct window_choose_data *cdata)
{
struct session *s;
struct window_pane *wp;
if (cdata == NULL)
return;
s = cdata->start_session;
if (!session_alive(s))
return;
wp = window_pane_at_index(cdata->wl->window, cdata->pane_id);
if (wp != NULL && window_pane_visible(wp))
window_set_active_pane(cdata->wl->window, wp);
if (session_select(s, cdata->idx) == 0) {
server_redraw_session(s);
recalculate_sizes();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -29,11 +29,10 @@
* Executes a tmux command if a shell command returns true or false. * Executes a tmux command if a shell command returns true or false.
*/ */
enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmdq_item *);
void cmd_if_shell_callback(struct job *); static void cmd_if_shell_callback(struct job *);
void cmd_if_shell_done(struct cmd_q *); static void cmd_if_shell_free(void *);
void cmd_if_shell_free(void *);
const struct cmd_entry cmd_if_shell_entry = { const struct cmd_entry cmd_if_shell_entry = {
.name = "if-shell", .name = "if-shell",
@@ -43,163 +42,180 @@ const struct cmd_entry cmd_if_shell_entry = {
.usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command " .usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command "
"[command]", "[command]",
.tflag = CMD_PANE_CANFAIL, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = 0, .flags = 0,
.exec = cmd_if_shell_exec .exec = cmd_if_shell_exec
}; };
struct cmd_if_shell_data { struct cmd_if_shell_data {
struct cmd_parse_input input;
char *cmd_if; char *cmd_if;
char *cmd_else; char *cmd_else;
struct cmd_q *cmdq; struct client *client;
struct cmdq_item *item;
struct mouse_event mouse; struct mouse_event mouse;
int bflag;
int references;
}; };
enum cmd_retval static enum cmd_retval
cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct mouse_event *m = &item->shared->mouse;
struct cmd_if_shell_data *cdata; struct cmd_if_shell_data *cdata;
char *shellcmd, *cmd, *cause; char *shellcmd, *cmd;
struct cmd_list *cmdlist; struct cmdq_item *new_item;
struct session *s = cmdq->state.tflag.s; struct cmd_find_state *fs = &item->target;
struct winlink *wl = cmdq->state.tflag.wl; struct client *c = cmd_find_client(item, NULL, 1);
struct window_pane *wp = cmdq->state.tflag.wp; struct session *s = fs->s;
struct format_tree *ft; struct winlink *wl = fs->wl;
const char *cwd; struct window_pane *wp = fs->wp;
struct cmd_parse_input pi;
if (cmdq->client != NULL && cmdq->client->session == NULL) struct cmd_parse_result *pr;
cwd = cmdq->client->cwd;
else if (s != NULL)
cwd = s->cwd;
else
cwd = NULL;
ft = format_create(cmdq, 0);
format_defaults(ft, cmdq->state.c, s, wl, wp);
shellcmd = format_expand(ft, args->argv[0]);
format_free(ft);
shellcmd = format_single(item, args->argv[0], c, s, wl, wp);
if (args_has(args, 'F')) { if (args_has(args, 'F')) {
cmd = NULL;
if (*shellcmd != '0' && *shellcmd != '\0') if (*shellcmd != '0' && *shellcmd != '\0')
cmd = args->argv[1]; cmd = args->argv[1];
else if (args->argc == 3) else if (args->argc == 3)
cmd = args->argv[2]; cmd = args->argv[2];
else
cmd = NULL;
free(shellcmd); free(shellcmd);
if (cmd == NULL) if (cmd == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) { memset(&pi, 0, sizeof pi);
cmdq_error(cmdq, "%s", cause); if (self->file != NULL)
free(cause); pi.file = self->file;
} pi.line = self->line;
pi.item = item;
pi.c = c;
cmd_find_copy_state(&pi.fs, fs);
pr = cmd_parse_from_string(cmd, &pi);
switch (pr->status) {
case CMD_PARSE_EMPTY:
break;
case CMD_PARSE_ERROR:
cmdq_error(item, "%s", pr->error);
free(pr->error);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, fs, m, 0);
cmdq_insert_after(item, new_item);
cmd_list_free(pr->cmdlist);
break;
} }
cmdq_run(cmdq, cmdlist, &cmdq->item->mouse);
cmd_list_free(cmdlist);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
cdata = xmalloc(sizeof *cdata); cdata = xcalloc(1, sizeof *cdata);
cdata->cmd_if = xstrdup(args->argv[1]); cdata->cmd_if = xstrdup(args->argv[1]);
if (args->argc == 3) if (args->argc == 3)
cdata->cmd_else = xstrdup(args->argv[2]); cdata->cmd_else = xstrdup(args->argv[2]);
else else
cdata->cmd_else = NULL; cdata->cmd_else = NULL;
memcpy(&cdata->mouse, m, sizeof cdata->mouse);
cdata->bflag = args_has(args, 'b'); if (!args_has(args, 'b'))
cdata->client = item->client;
else
cdata->client = c;
if (cdata->client != NULL)
cdata->client->references++;
cdata->cmdq = cmdq; if (!args_has(args, 'b'))
memcpy(&cdata->mouse, &cmdq->item->mouse, sizeof cdata->mouse); cdata->item = item;
cmdq->references++; else
cdata->item = NULL;
cdata->references = 1; memset(&cdata->input, 0, sizeof cdata->input);
job_run(shellcmd, s, cwd, cmd_if_shell_callback, cmd_if_shell_free, if (self->file != NULL)
cdata); cdata->input.file = xstrdup(self->file);
cdata->input.line = self->line;
cdata->input.item = cdata->item;
cdata->input.c = c;
if (cdata->input.c != NULL)
cdata->input.c->references++;
cmd_find_copy_state(&cdata->input.fs, fs);
if (job_run(shellcmd, s, server_client_get_cwd(item->client, s), NULL,
cmd_if_shell_callback, cmd_if_shell_free, cdata, 0) == NULL) {
cmdq_error(item, "failed to run command: %s", shellcmd);
free(shellcmd);
free(cdata);
return (CMD_RETURN_ERROR);
}
free(shellcmd); free(shellcmd);
if (cdata->bflag) if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
void static void
cmd_if_shell_callback(struct job *job) cmd_if_shell_callback(struct job *job)
{ {
struct cmd_if_shell_data *cdata = job->data; struct cmd_if_shell_data *cdata = job_get_data(job);
struct cmd_q *cmdq = cdata->cmdq, *cmdq1; struct client *c = cdata->client;
struct cmd_list *cmdlist; struct mouse_event *m = &cdata->mouse;
char *cause, *cmd; struct cmdq_item *new_item = NULL;
char *cmd;
int status;
struct cmd_parse_result *pr;
if (cmdq->flags & CMD_Q_DEAD) status = job_get_status(job);
return; if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
cmd = cdata->cmd_else; cmd = cdata->cmd_else;
else else
cmd = cdata->cmd_if; cmd = cdata->cmd_if;
if (cmd == NULL) if (cmd == NULL)
return; goto out;
if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) { pr = cmd_parse_from_string(cmd, &cdata->input);
if (cause != NULL) { switch (pr->status) {
cmdq_error(cmdq, "%s", cause); case CMD_PARSE_EMPTY:
free(cause); break;
} case CMD_PARSE_ERROR:
return; if (cdata->item != NULL)
cmdq_error(cdata->item, "%s", pr->error);
free(pr->error);
break;
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, NULL, m, 0);
cmd_list_free(pr->cmdlist);
break;
}
if (new_item != NULL) {
if (cdata->item == NULL)
cmdq_append(c, new_item);
else
cmdq_insert_after(cdata->item, new_item);
} }
cmdq1 = cmdq_new(cmdq->client); out:
cmdq1->flags |= cmdq->flags & CMD_Q_NOHOOKS; if (cdata->item != NULL)
cmdq1->emptyfn = cmd_if_shell_done; cmdq_continue(cdata->item);
cmdq1->data = cdata;
cdata->references++;
cmdq_run(cmdq1, cmdlist, &cdata->mouse);
cmd_list_free(cmdlist);
} }
void static void
cmd_if_shell_done(struct cmd_q *cmdq1)
{
struct cmd_if_shell_data *cdata = cmdq1->data;
struct cmd_q *cmdq = cdata->cmdq;
if (cmdq1->client_exit >= 0)
cmdq->client_exit = cmdq1->client_exit;
cmdq_free(cmdq1);
if (--cdata->references != 0)
return;
if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq);
free(cdata->cmd_else);
free(cdata->cmd_if);
free(cdata);
}
void
cmd_if_shell_free(void *data) cmd_if_shell_free(void *data)
{ {
struct cmd_if_shell_data *cdata = data; struct cmd_if_shell_data *cdata = data;
struct cmd_q *cmdq = cdata->cmdq;
if (--cdata->references != 0) if (cdata->client != NULL)
return; server_client_unref(cdata->client);
if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq);
free(cdata->cmd_else); free(cdata->cmd_else);
free(cdata->cmd_if); free(cdata->cmd_if);
if (cdata->input.c != NULL)
server_client_unref(cdata->input.c);
free((void *)cdata->input.file);
free(cdata); free(cdata);
} }

View File

@@ -28,9 +28,7 @@
* Join or move a pane into another (like split/swap/kill). * Join or move a pane into another (like split/swap/kill).
*/ */
enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmdq_item *);
enum cmd_retval join_pane(struct cmd *, struct cmd_q *, int);
const struct cmd_entry cmd_join_pane_entry = { const struct cmd_entry cmd_join_pane_entry = {
.name = "join-pane", .name = "join-pane",
@@ -39,8 +37,8 @@ const struct cmd_entry cmd_join_pane_entry = {
.args = { "bdhvp:l:s:t:", 0, 0 }, .args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE, .usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.sflag = CMD_PANE_MARKED, .source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_join_pane_exec .exec = cmd_join_pane_exec
@@ -53,23 +51,18 @@ const struct cmd_entry cmd_move_pane_entry = {
.args = { "bdhvp:l:s:t:", 0, 0 }, .args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE, .usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.sflag = CMD_PANE, .source = { 's', CMD_FIND_PANE, 0 },
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_join_pane_exec .exec = cmd_join_pane_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_join_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
{
return (join_pane(self, cmdq, self->entry == &cmd_join_pane_entry));
}
enum cmd_retval
join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct session *dst_s; struct session *dst_s;
struct winlink *src_wl, *dst_wl; struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w; struct window *src_w, *dst_w;
@@ -78,25 +71,31 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
int size, percentage, dst_idx; int size, percentage, dst_idx;
enum layout_type type; enum layout_type type;
struct layout_cell *lc; struct layout_cell *lc;
int not_same_window, flags;
dst_s = cmdq->state.tflag.s; if (self->entry == &cmd_join_pane_entry)
dst_wl = cmdq->state.tflag.wl; not_same_window = 1;
dst_wp = cmdq->state.tflag.wp; else
not_same_window = 0;
dst_s = item->target.s;
dst_wl = item->target.wl;
dst_wp = item->target.wp;
dst_w = dst_wl->window; dst_w = dst_wl->window;
dst_idx = dst_wl->idx; dst_idx = dst_wl->idx;
server_unzoom_window(dst_w); server_unzoom_window(dst_w);
src_wl = cmdq->state.sflag.wl; src_wl = item->source.wl;
src_wp = cmdq->state.sflag.wp; src_wp = item->source.wp;
src_w = src_wl->window; src_w = src_wl->window;
server_unzoom_window(src_w); server_unzoom_window(src_w);
if (not_same_window && src_w == dst_w) { if (not_same_window && src_w == dst_w) {
cmdq_error(cmdq, "can't join a pane to its own window"); cmdq_error(item, "can't join a pane to its own window");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (!not_same_window && src_wp == dst_wp) { if (!not_same_window && src_wp == dst_wp) {
cmdq_error(cmdq, "source and target panes must be different"); cmdq_error(item, "source and target panes must be different");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -108,14 +107,14 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
if (args_has(args, 'l')) { if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause); size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(cmdq, "size %s", cause); cmdq_error(item, "size %s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else if (args_has(args, 'p')) { } else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, 100, &cause); percentage = args_strtonum(args, 'p', 0, 100, &cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(cmdq, "percentage %s", cause); cmdq_error(item, "percentage %s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -124,9 +123,13 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
else else
size = (dst_wp->sx * percentage) / 100; size = (dst_wp->sx * percentage) / 100;
} }
lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'), 0); if (args_has(args, 'b'))
flags = SPAWN_BEFORE;
else
flags = 0;
lc = layout_split_pane(dst_wp, type, size, flags);
if (lc == NULL) { if (lc == NULL) {
cmdq_error(cmdq, "create pane failed: pane too small"); cmdq_error(item, "create pane failed: pane too small");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -136,6 +139,8 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
TAILQ_REMOVE(&src_w->panes, src_wp, entry); TAILQ_REMOVE(&src_w->panes, src_wp, entry);
src_wp->window = dst_w; src_wp->window = dst_w;
options_set_parent(src_wp->options, dst_w->options);
src_wp->flags |= PANE_STYLECHANGED;
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry); TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp); layout_assign_pane(lc, src_wp);
@@ -145,8 +150,9 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
server_redraw_window(dst_w); server_redraw_window(dst_w);
if (!args_has(args, 'd')) { if (!args_has(args, 'd')) {
window_set_active_pane(dst_w, src_wp); window_set_active_pane(dst_w, src_wp, 1);
session_select(dst_s, dst_idx); session_select(dst_s, dst_idx);
cmd_find_from_session(current, dst_s, 0);
server_redraw_session(dst_s); server_redraw_session(dst_s);
} else } else
server_status_session(dst_s); server_status_session(dst_s);
@@ -154,8 +160,8 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
if (window_count_panes(src_w) == 0) if (window_count_panes(src_w) == 0)
server_kill_window(src_w); server_kill_window(src_w);
else else
notify_window_layout_changed(src_w); notify_window("window-layout-changed", src_w);
notify_window_layout_changed(dst_w); notify_window("window-layout-changed", dst_w);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -26,7 +26,7 @@
* Kill pane. * Kill pane.
*/ */
enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_kill_pane_entry = { const struct cmd_entry cmd_kill_pane_entry = {
.name = "kill-pane", .name = "kill-pane",
@@ -35,39 +35,30 @@ const struct cmd_entry cmd_kill_pane_entry = {
.args = { "at:", 0, 0 }, .args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_PANE_USAGE, .usage = "[-a] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_kill_pane_exec .exec = cmd_kill_pane_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_kill_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct winlink *wl = cmdq->state.tflag.wl; struct winlink *wl = item->target.wl;
struct window_pane *loopwp, *tmpwp, *wp = cmdq->state.tflag.wp; struct window_pane *loopwp, *tmpwp, *wp = item->target.wp;
server_unzoom_window(wl->window);
if (window_count_panes(wl->window) == 1) {
/* Only one pane, kill the window. */
server_kill_window(wl->window);
recalculate_sizes();
return (CMD_RETURN_NORMAL);
}
if (args_has(self->args, 'a')) { if (args_has(self->args, 'a')) {
server_unzoom_window(wl->window);
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) { TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
if (loopwp == wp) if (loopwp == wp)
continue; continue;
layout_close_pane(loopwp); layout_close_pane(loopwp);
window_remove_pane(wl->window, loopwp); window_remove_pane(wl->window, loopwp);
} }
} else { server_redraw_window(wl->window);
layout_close_pane(wp); return (CMD_RETURN_NORMAL);
window_remove_pane(wl->window, wp);
} }
server_redraw_window(wl->window);
server_kill_pane(wp);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -27,7 +27,7 @@
* Kill the server and do nothing else. * Kill the server and do nothing else.
*/ */
enum cmd_retval cmd_kill_server_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_kill_server_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_kill_server_entry = { const struct cmd_entry cmd_kill_server_entry = {
.name = "kill-server", .name = "kill-server",
@@ -51,8 +51,8 @@ const struct cmd_entry cmd_start_server_entry = {
.exec = cmd_kill_server_exec .exec = cmd_kill_server_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_kill_server_exec(struct cmd *self, __unused struct cmd_q *cmdq) cmd_kill_server_exec(struct cmd *self, __unused struct cmdq_item *item)
{ {
if (self->entry == &cmd_kill_server_entry) if (self->entry == &cmd_kill_server_entry)
kill(getpid(), SIGTERM); kill(getpid(), SIGTERM);

View File

@@ -27,7 +27,7 @@
* Note this deliberately has no alias to make it hard to hit by accident. * Note this deliberately has no alias to make it hard to hit by accident.
*/ */
enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_kill_session_entry = { const struct cmd_entry cmd_kill_session_entry = {
.name = "kill-session", .name = "kill-session",
@@ -36,20 +36,20 @@ const struct cmd_entry cmd_kill_session_entry = {
.args = { "aCt:", 0, 0 }, .args = { "aCt:", 0, 0 },
.usage = "[-aC] " CMD_TARGET_SESSION_USAGE, .usage = "[-aC] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0, .flags = 0,
.exec = cmd_kill_session_exec .exec = cmd_kill_session_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_kill_session_exec(struct cmd *self, struct cmd_q *cmdq) cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s, *sloop, *stmp; struct session *s, *sloop, *stmp;
struct winlink *wl; struct winlink *wl;
s = cmdq->state.tflag.s; s = item->target.s;
if (args_has(args, 'C')) { if (args_has(args, 'C')) {
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
@@ -61,12 +61,12 @@ cmd_kill_session_exec(struct cmd *self, struct cmd_q *cmdq)
RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) { RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) {
if (sloop != s) { if (sloop != s) {
server_destroy_session(sloop); server_destroy_session(sloop);
session_destroy(sloop); session_destroy(sloop, 1, __func__);
} }
} }
} else { } else {
server_destroy_session(s); server_destroy_session(s);
session_destroy(s); session_destroy(s, 1, __func__);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -24,7 +24,7 @@
* Destroy window. * Destroy window.
*/ */
enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_kill_window_entry = { const struct cmd_entry cmd_kill_window_entry = {
.name = "kill-window", .name = "kill-window",
@@ -33,7 +33,7 @@ const struct cmd_entry cmd_kill_window_entry = {
.args = { "at:", 0, 0 }, .args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_WINDOW_USAGE, .usage = "[-a] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_kill_window_exec .exec = cmd_kill_window_exec
@@ -46,23 +46,23 @@ const struct cmd_entry cmd_unlink_window_entry = {
.args = { "kt:", 0, 0 }, .args = { "kt:", 0, 0 },
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE, .usage = "[-k] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_kill_window_exec .exec = cmd_kill_window_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_kill_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = cmdq->state.tflag.wl, *wl2, *wl3; struct winlink *wl = item->target.wl, *wl2, *wl3;
struct window *w = wl->window; struct window *w = wl->window;
struct session *s = cmdq->state.tflag.s; struct session *s = item->target.s;
if (self->entry == &cmd_unlink_window_entry) { if (self->entry == &cmd_unlink_window_entry) {
if (!args_has(self->args, 'k') && !session_is_linked(s, w)) { if (!args_has(self->args, 'k') && !session_is_linked(s, w)) {
cmdq_error(cmdq, "window only linked to one session"); cmdq_error(item, "window only linked to one session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
server_unlink_window(s, wl); server_unlink_window(s, wl);

View File

@@ -30,7 +30,7 @@
#define LIST_BUFFERS_TEMPLATE \ #define LIST_BUFFERS_TEMPLATE \
"#{buffer_name}: #{buffer_size} bytes: \"#{buffer_sample}\"" "#{buffer_name}: #{buffer_size} bytes: \"#{buffer_sample}\""
enum cmd_retval cmd_list_buffers_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_list_buffers_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_list_buffers_entry = { const struct cmd_entry cmd_list_buffers_entry = {
.name = "list-buffers", .name = "list-buffers",
@@ -39,12 +39,12 @@ const struct cmd_entry cmd_list_buffers_entry = {
.args = { "F:", 0, 0 }, .args = { "F:", 0, 0 },
.usage = "[-F format]", .usage = "[-F format]",
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_list_buffers_exec .exec = cmd_list_buffers_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_list_buffers_exec(struct cmd *self, struct cmd_q *cmdq) cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct paste_buffer *pb; struct paste_buffer *pb;
@@ -57,11 +57,11 @@ cmd_list_buffers_exec(struct cmd *self, struct cmd_q *cmdq)
pb = NULL; pb = NULL;
while ((pb = paste_walk(pb)) != NULL) { while ((pb = paste_walk(pb)) != NULL) {
ft = format_create(cmdq, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults_paste_buffer(ft, pb); format_defaults_paste_buffer(ft, pb);
line = format_expand(ft, template); line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line); cmdq_print(item, "%s", line);
free(line); free(line);
format_free(ft); format_free(ft);

View File

@@ -29,11 +29,11 @@
*/ */
#define LIST_CLIENTS_TEMPLATE \ #define LIST_CLIENTS_TEMPLATE \
"#{client_tty}: #{session_name} " \ "#{client_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}]" \ "[#{client_width}x#{client_height} #{client_termname}]" \
"#{?client_utf8, (utf8),} #{?client_readonly, (ro),}" "#{?client_utf8, (utf8),} #{?client_readonly, (ro),}"
enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_list_clients_entry = { const struct cmd_entry cmd_list_clients_entry = {
.name = "list-clients", .name = "list-clients",
@@ -42,14 +42,14 @@ const struct cmd_entry cmd_list_clients_entry = {
.args = { "F:t:", 0, 0 }, .args = { "F:t:", 0, 0 },
.usage = "[-F format] " CMD_TARGET_SESSION_USAGE, .usage = "[-F format] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_READONLY, .flags = CMD_READONLY|CMD_AFTERHOOK,
.exec = cmd_list_clients_exec .exec = cmd_list_clients_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_list_clients_exec(struct cmd *self, struct cmd_q *cmdq) cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c;
@@ -60,7 +60,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_q *cmdq)
char *line; char *line;
if (args_has(args, 't')) if (args_has(args, 't'))
s = cmdq->state.tflag.s; s = item->target.s;
else else
s = NULL; s = NULL;
@@ -72,12 +72,12 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_q *cmdq)
if (c->session == NULL || (s != NULL && s != c->session)) if (c->session == NULL || (s != NULL && s != c->session))
continue; continue;
ft = format_create(cmdq, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", idx); format_add(ft, "line", "%u", idx);
format_defaults(ft, c, NULL, NULL, NULL); format_defaults(ft, c, NULL, NULL, NULL);
line = format_expand(ft, template); line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line); cmdq_print(item, "%s", line);
free(line); free(line);
format_free(ft); format_free(ft);

View File

@@ -27,19 +27,19 @@
* List key bindings. * List key bindings.
*/ */
static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmdq_item *);
static enum cmd_retval cmd_list_keys_table(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_list_keys_commands(struct cmd *,
static enum cmd_retval cmd_list_keys_commands(struct cmd *, struct cmd_q *); struct cmdq_item *);
const struct cmd_entry cmd_list_keys_entry = { const struct cmd_entry cmd_list_keys_entry = {
.name = "list-keys", .name = "list-keys",
.alias = "lsk", .alias = "lsk",
.args = { "t:T:", 0, 0 }, .args = { "T:", 0, 0 },
.usage = "[-t mode-table] [-T key-table]", .usage = "[-T key-table]",
.flags = CMD_STARTSERVER, .flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_keys_exec .exec = cmd_list_keys_exec
}; };
@@ -50,41 +50,43 @@ const struct cmd_entry cmd_list_commands_entry = {
.args = { "F:", 0, 0 }, .args = { "F:", 0, 0 },
.usage = "[-F format]", .usage = "[-F format]",
.flags = CMD_STARTSERVER, .flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_keys_exec .exec = cmd_list_keys_exec
}; };
static enum cmd_retval static enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq) cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct key_table *table; struct key_table *table;
struct key_binding *bd; struct key_binding *bd;
const char *key, *tablename, *r; const char *tablename, *r;
char *cp, tmp[BUFSIZ]; char *key, *cp, *tmp;
int repeat, width, tablewidth, keywidth; int repeat, width, tablewidth, keywidth;
size_t tmpsize, tmpused, cplen;
if (self->entry == &cmd_list_commands_entry) if (self->entry == &cmd_list_commands_entry)
return (cmd_list_keys_commands(self, cmdq)); return (cmd_list_keys_commands(self, item));
if (args_has(args, 't'))
return (cmd_list_keys_table(self, cmdq));
tablename = args_get(args, 'T'); tablename = args_get(args, 'T');
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) { if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(cmdq, "table %s doesn't exist", tablename); cmdq_error(item, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
repeat = 0; repeat = 0;
tablewidth = keywidth = 0; tablewidth = keywidth = 0;
RB_FOREACH(table, key_tables, &key_tables) { table = key_bindings_first_table ();
if (tablename != NULL && strcmp(table->name, tablename) != 0) while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table);
continue; continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) { }
key = key_string_lookup_key(bd->key); bd = key_bindings_first(table);
while (bd != NULL) {
key = args_escape(key_string_lookup_key(bd->key));
if (bd->can_repeat) if (bd->flags & KEY_BINDING_REPEAT)
repeat = 1; repeat = 1;
width = utf8_cstrwidth(table->name); width = utf8_cstrwidth(table->name);
@@ -93,114 +95,84 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
width = utf8_cstrwidth(key); width = utf8_cstrwidth(key);
if (width > keywidth) if (width > keywidth)
keywidth = width; keywidth = width;
free(key);
bd = key_bindings_next(table, bd);
} }
table = key_bindings_next_table(table);
} }
RB_FOREACH(table, key_tables, &key_tables) { tmpsize = 256;
if (tablename != NULL && strcmp(table->name, tablename) != 0) tmp = xmalloc(tmpsize);
table = key_bindings_first_table ();
while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table);
continue; continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) { }
key = key_string_lookup_key(bd->key); bd = key_bindings_first(table);
while (bd != NULL) {
key = args_escape(key_string_lookup_key(bd->key));
if (!repeat) if (!repeat)
r = ""; r = "";
else if (bd->can_repeat) else if (bd->flags & KEY_BINDING_REPEAT)
r = "-r "; r = "-r ";
else else
r = " "; r = " ";
xsnprintf(tmp, sizeof tmp, "%s-T ", r); tmpused = xsnprintf(tmp, tmpsize, "%s-T ", r);
cp = utf8_padcstr(table->name, tablewidth); cp = utf8_padcstr(table->name, tablewidth);
strlcat(tmp, cp, sizeof tmp); cplen = strlen(cp) + 1;
strlcat(tmp, " ", sizeof tmp); while (tmpused + cplen + 1 >= tmpsize) {
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
tmpused = strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize);
free(cp); free(cp);
cp = utf8_padcstr(key, keywidth); cp = utf8_padcstr(key, keywidth);
strlcat(tmp, cp, sizeof tmp); cplen = strlen(cp) + 1;
strlcat(tmp, " ", sizeof tmp); while (tmpused + cplen + 1 >= tmpsize) {
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
tmpused = strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize);
free(cp); free(cp);
cp = cmd_list_print(bd->cmdlist); cp = cmd_list_print(bd->cmdlist, 1);
strlcat(tmp, cp, sizeof tmp); cplen = strlen(cp);
while (tmpused + cplen + 1 >= tmpsize) {
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
strlcat(tmp, cp, tmpsize);
free(cp); free(cp);
cmdq_print(cmdq, "bind-key %s", tmp); cmdq_print(item, "bind-key %s", tmp);
free(key);
bd = key_bindings_next(table, bd);
} }
table = key_bindings_next_table(table);
} }
free(tmp);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
static enum cmd_retval static enum cmd_retval
cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq) cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
const char *tablename, *key, *cmdstr, *mode;
const struct mode_key_table *mtab;
struct mode_key_binding *mbind;
char repeat[16];
int width, keywidth, repeatwidth, any_mode;
tablename = args_get(args, 't');
if ((mtab = mode_key_findtable(tablename)) == NULL) {
cmdq_error(cmdq, "unknown key table: %s", tablename);
return (CMD_RETURN_ERROR);
}
keywidth = repeatwidth = 0;
any_mode = 0;
RB_FOREACH(mbind, mode_key_tree, mtab->tree) {
key = key_string_lookup_key(mbind->key);
if (mbind->mode != 0)
any_mode = 1;
width = strlen(key);
if (width > keywidth)
keywidth = width;
if (mbind->repeat != 1) {
snprintf(repeat, sizeof repeat, "%u", mbind->repeat);
width = strlen(repeat);
if (width > repeatwidth)
repeatwidth = width;
}
}
RB_FOREACH(mbind, mode_key_tree, mtab->tree) {
key = key_string_lookup_key(mbind->key);
mode = "";
if (mbind->mode != 0)
mode = "c";
snprintf(repeat, sizeof repeat, "%u", mbind->repeat);
cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd);
if (cmdstr != NULL) {
cmdq_print(cmdq,
"bind-key -%st %s%s%s%*s %*s %s%s%s%s",
mode, any_mode && *mode == '\0' ? " " : "",
mtab->name,
mbind->repeat != 1 ? " -R " :
(repeatwidth == 0 ? "" : " "),
repeatwidth, mbind->repeat != 1 ? repeat : "",
(int)keywidth, key, cmdstr,
mbind->arg != NULL ? " \"" : "",
mbind->arg != NULL ? mbind->arg : "",
mbind->arg != NULL ? "\"": "");
}
}
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_list_keys_commands(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
const struct cmd_entry **entryp; const struct cmd_entry **entryp;
const struct cmd_entry *entry; const struct cmd_entry *entry;
struct format_tree *ft; struct format_tree *ft;
const char *template; const char *template, *s;
char *line; char *line;
if ((template = args_get(args, 'F')) == NULL) { if ((template = args_get(args, 'F')) == NULL) {
@@ -209,25 +181,27 @@ cmd_list_keys_commands(struct cmd *self, struct cmd_q *cmdq)
"#{command_list_usage}"; "#{command_list_usage}";
} }
ft = format_create(cmdq, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, NULL, NULL, NULL, NULL); format_defaults(ft, NULL, NULL, NULL, NULL);
for (entryp = cmd_table; *entryp != NULL; entryp++) { for (entryp = cmd_table; *entryp != NULL; entryp++) {
entry = *entryp; entry = *entryp;
format_add(ft, "command_list_name", "%s", entry->name); format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL) { if (entry->alias != NULL)
format_add(ft, "command_list_alias", "%s", s = entry->alias;
entry->alias); else
} s = "";
if (entry->alias != NULL) { format_add(ft, "command_list_alias", "%s", s);
format_add(ft, "command_list_usage", "%s", if (entry->usage != NULL)
entry->usage); s = entry->usage;
} else
s = "";
format_add(ft, "command_list_usage", "%s", s);
line = format_expand(ft, template); line = format_expand(ft, template);
if (*line != '\0') if (*line != '\0')
cmdq_print(cmdq, "%s", line); cmdq_print(item, "%s", line);
free(line); free(line);
} }

View File

@@ -26,13 +26,13 @@
* List panes on given window. * List panes on given window.
*/ */
enum cmd_retval cmd_list_panes_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_list_panes_exec(struct cmd *, struct cmdq_item *);
void cmd_list_panes_server(struct cmd *, struct cmd_q *); static void cmd_list_panes_server(struct cmd *, struct cmdq_item *);
void cmd_list_panes_session(struct cmd *, struct session *, struct cmd_q *, static void cmd_list_panes_session(struct cmd *, struct session *,
int); struct cmdq_item *, int);
void cmd_list_panes_window(struct cmd *, struct session *, struct winlink *, static void cmd_list_panes_window(struct cmd *, struct session *,
struct cmd_q *, int); struct winlink *, struct cmdq_item *, int);
const struct cmd_entry cmd_list_panes_entry = { const struct cmd_entry cmd_list_panes_entry = {
.name = "list-panes", .name = "list-panes",
@@ -41,51 +41,51 @@ const struct cmd_entry cmd_list_panes_entry = {
.args = { "asF:t:", 0, 0 }, .args = { "asF:t:", 0, 0 },
.usage = "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE, .usage = "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_list_panes_exec .exec = cmd_list_panes_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_list_panes_exec(struct cmd *self, struct cmd_q *cmdq) cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s = cmdq->state.tflag.s; struct session *s = item->target.s;
struct winlink *wl = cmdq->state.tflag.wl; struct winlink *wl = item->target.wl;
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_panes_server(self, cmdq); cmd_list_panes_server(self, item);
else if (args_has(args, 's')) else if (args_has(args, 's'))
cmd_list_panes_session(self, s, cmdq, 1); cmd_list_panes_session(self, s, item, 1);
else else
cmd_list_panes_window(self, s, wl, cmdq, 0); cmd_list_panes_window(self, s, wl, item, 0);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
void static void
cmd_list_panes_server(struct cmd *self, struct cmd_q *cmdq) cmd_list_panes_server(struct cmd *self, struct cmdq_item *item)
{ {
struct session *s; struct session *s;
RB_FOREACH(s, sessions, &sessions) RB_FOREACH(s, sessions, &sessions)
cmd_list_panes_session(self, s, cmdq, 2); cmd_list_panes_session(self, s, item, 2);
} }
void static void
cmd_list_panes_session(struct cmd *self, struct session *s, struct cmd_q *cmdq, cmd_list_panes_session(struct cmd *self, struct session *s,
int type) struct cmdq_item *item, int type)
{ {
struct winlink *wl; struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows) RB_FOREACH(wl, winlinks, &s->windows)
cmd_list_panes_window(self, s, wl, cmdq, type); cmd_list_panes_window(self, s, wl, item, type);
} }
void static void
cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl, cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
struct cmd_q *cmdq, int type) struct cmdq_item *item, int type)
{ {
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp; struct window_pane *wp;
@@ -123,12 +123,12 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
n = 0; n = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) { TAILQ_FOREACH(wp, &wl->window->panes, entry) {
ft = format_create(cmdq, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, wp); format_defaults(ft, NULL, s, wl, wp);
line = format_expand(ft, template); line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line); cmdq_print(item, "%s", line);
free(line); free(line);
format_free(ft); format_free(ft);

View File

@@ -30,13 +30,13 @@
#define LIST_SESSIONS_TEMPLATE \ #define LIST_SESSIONS_TEMPLATE \
"#{session_name}: #{session_windows} windows " \ "#{session_name}: #{session_windows} windows " \
"(created #{t:session_created}) " \ "(created #{t:session_created})" \
"[#{session_width}x#{session_height}]" \
"#{?session_grouped, (group ,}" \ "#{?session_grouped, (group ,}" \
"#{session_group}#{?session_grouped,),}" \ "#{session_group}#{?session_grouped,),}" \
"#{?session_attached, (attached),}" "#{?session_attached, (attached),}"
enum cmd_retval cmd_list_sessions_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_list_sessions_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_list_sessions_entry = { const struct cmd_entry cmd_list_sessions_entry = {
.name = "list-sessions", .name = "list-sessions",
@@ -45,12 +45,12 @@ const struct cmd_entry cmd_list_sessions_entry = {
.args = { "F:", 0, 0 }, .args = { "F:", 0, 0 },
.usage = "[-F format]", .usage = "[-F format]",
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_list_sessions_exec .exec = cmd_list_sessions_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_list_sessions_exec(struct cmd *self, struct cmd_q *cmdq) cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s;
@@ -64,12 +64,12 @@ cmd_list_sessions_exec(struct cmd *self, struct cmd_q *cmdq)
n = 0; n = 0;
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
ft = format_create(cmdq, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, NULL, NULL); format_defaults(ft, NULL, s, NULL, NULL);
line = format_expand(ft, template); line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line); cmdq_print(item, "%s", line);
free(line); free(line);
format_free(ft); format_free(ft);

View File

@@ -39,11 +39,11 @@
"(#{window_panes} panes) " \ "(#{window_panes} panes) " \
"[#{window_width}x#{window_height}] " "[#{window_width}x#{window_height}] "
enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmdq_item *);
void cmd_list_windows_server(struct cmd *, struct cmd_q *); static void cmd_list_windows_server(struct cmd *, struct cmdq_item *);
void cmd_list_windows_session(struct cmd *, struct session *, static void cmd_list_windows_session(struct cmd *, struct session *,
struct cmd_q *, int); struct cmdq_item *, int);
const struct cmd_entry cmd_list_windows_entry = { const struct cmd_entry cmd_list_windows_entry = {
.name = "list-windows", .name = "list-windows",
@@ -52,41 +52,41 @@ const struct cmd_entry cmd_list_windows_entry = {
.args = { "F:at:", 0, 0 }, .args = { "F:at:", 0, 0 },
.usage = "[-a] [-F format] " CMD_TARGET_SESSION_USAGE, .usage = "[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_list_windows_exec .exec = cmd_list_windows_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_list_windows_exec(struct cmd *self, struct cmd_q *cmdq) cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_windows_server(self, cmdq); cmd_list_windows_server(self, item);
else else
cmd_list_windows_session(self, cmdq->state.tflag.s, cmdq, 0); cmd_list_windows_session(self, item->target.s, item, 0);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
void static void
cmd_list_windows_server(struct cmd *self, struct cmd_q *cmdq) cmd_list_windows_server(struct cmd *self, struct cmdq_item *item)
{ {
struct session *s; struct session *s;
RB_FOREACH(s, sessions, &sessions) RB_FOREACH(s, sessions, &sessions)
cmd_list_windows_session(self, s, cmdq, 1); cmd_list_windows_session(self, s, item, 1);
} }
void static void
cmd_list_windows_session(struct cmd *self, struct session *s, cmd_list_windows_session(struct cmd *self, struct session *s,
struct cmd_q *cmdq, int type) struct cmdq_item *item, int type)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
u_int n; u_int n;
struct format_tree *ft; struct format_tree *ft;
const char *template; const char *template;
char *line; char *line;
@@ -105,12 +105,12 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
n = 0; n = 0;
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
ft = format_create(cmdq, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, NULL); format_defaults(ft, NULL, s, wl, NULL);
line = format_expand(ft, template); line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line); cmdq_print(item, "%s", line);
free(line); free(line);
format_free(ft); format_free(ft);

View File

@@ -1,126 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
struct cmd_list *
cmd_list_parse(int argc, char **argv, const char *file, u_int line,
char **cause)
{
struct cmd_list *cmdlist;
struct cmd *cmd;
int i, lastsplit;
size_t arglen, new_argc;
char **copy_argv, **new_argv;
copy_argv = cmd_copy_argv(argc, argv);
cmdlist = xcalloc(1, sizeof *cmdlist);
cmdlist->references = 1;
TAILQ_INIT(&cmdlist->list);
lastsplit = 0;
for (i = 0; i < argc; i++) {
arglen = strlen(copy_argv[i]);
if (arglen == 0 || copy_argv[i][arglen - 1] != ';')
continue;
copy_argv[i][arglen - 1] = '\0';
if (arglen > 1 && copy_argv[i][arglen - 2] == '\\') {
copy_argv[i][arglen - 2] = ';';
continue;
}
new_argc = i - lastsplit;
new_argv = copy_argv + lastsplit;
if (arglen != 1)
new_argc++;
cmd = cmd_parse(new_argc, new_argv, file, line, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
lastsplit = i + 1;
}
if (lastsplit != argc) {
cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit,
file, line, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
}
cmd_free_argv(argc, copy_argv);
return (cmdlist);
bad:
cmd_list_free(cmdlist);
cmd_free_argv(argc, copy_argv);
return (NULL);
}
void
cmd_list_free(struct cmd_list *cmdlist)
{
struct cmd *cmd, *cmd1;
if (--cmdlist->references != 0)
return;
TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) {
TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
args_free(cmd->args);
free(cmd->file);
free(cmd);
}
free(cmdlist);
}
char *
cmd_list_print(struct cmd_list *cmdlist)
{
struct cmd *cmd;
char *buf, *this;
size_t len;
len = 1;
buf = xcalloc(1, len);
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
this = cmd_print(cmd);
len += strlen(this) + 3;
buf = xrealloc(buf, len);
strlcat(buf, this, len);
if (TAILQ_NEXT(cmd, qentry) != NULL)
strlcat(buf, " ; ", len);
free(this);
}
return (buf);
}

View File

@@ -31,8 +31,9 @@
* Loads a paste buffer from a file. * Loads a paste buffer from a file.
*/ */
enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmdq_item *);
void cmd_load_buffer_callback(struct client *, int, void *);
static void cmd_load_buffer_callback(struct client *, int, void *);
const struct cmd_entry cmd_load_buffer_entry = { const struct cmd_entry cmd_load_buffer_entry = {
.name = "load-buffer", .name = "load-buffer",
@@ -41,59 +42,64 @@ const struct cmd_entry cmd_load_buffer_entry = {
.args = { "b:", 1, 1 }, .args = { "b:", 1, 1 },
.usage = CMD_BUFFER_USAGE " path", .usage = CMD_BUFFER_USAGE " path",
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_load_buffer_exec .exec = cmd_load_buffer_exec
}; };
enum cmd_retval struct cmd_load_buffer_data {
cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq) struct cmdq_item *item;
char *bufname;
};
static enum cmd_retval
cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmdq->client; struct cmd_load_buffer_data *cdata;
struct session *s; struct client *c = cmd_find_client(item, NULL, 1);
FILE *f; struct session *s = item->target.s;
const char *path, *bufname, *cwd; struct winlink *wl = item->target.wl;
char *pdata, *new_pdata, *cause, *file, resolved[PATH_MAX]; struct window_pane *wp = item->target.wp;
size_t psize; FILE *f;
int ch, error; const char *bufname;
char *pdata = NULL, *new_pdata, *cause;
char *path, *file;
size_t psize;
int ch, error;
bufname = NULL; bufname = NULL;
if (args_has(args, 'b')) if (args_has(args, 'b'))
bufname = args_get(args, 'b'); bufname = args_get(args, 'b');
path = args->argv[0]; path = format_single(item, args->argv[0], c, s, wl, wp);
if (strcmp(path, "-") == 0) { if (strcmp(path, "-") == 0) {
free(path);
c = item->client;
cdata = xcalloc(1, sizeof *cdata);
cdata->item = item;
if (bufname != NULL)
cdata->bufname = xstrdup(bufname);
error = server_set_stdin_callback(c, cmd_load_buffer_callback, error = server_set_stdin_callback(c, cmd_load_buffer_callback,
(void *)bufname, &cause); cdata, &cause);
if (error != 0) { if (error != 0) {
cmdq_error(cmdq, "%s: %s", path, cause); cmdq_error(item, "-: %s", cause);
free(cause); free(cause);
free(cdata);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
if (c != NULL && c->session == NULL && c->cwd != NULL) file = server_client_get_path(item->client, path);
cwd = c->cwd; free(path);
else if ((s = c->session) != NULL && s->cwd != NULL)
cwd = s->cwd;
else
cwd = ".";
if (*path == '/') f = fopen(file, "rb");
file = xstrdup(path);
else
xasprintf(&file, "%s/%s", cwd, path);
if (realpath(file, resolved) == NULL &&
strlcpy(resolved, file, sizeof resolved) >= sizeof resolved) {
cmdq_error(cmdq, "%s: %s", file, strerror(ENAMETOOLONG));
return (CMD_RETURN_ERROR);
}
f = fopen(resolved, "rb");
free(file);
if (f == NULL) { if (f == NULL) {
cmdq_error(cmdq, "%s: %s", resolved, strerror(errno)); cmdq_error(item, "%s: %s", file, strerror(errno));
return (CMD_RETURN_ERROR); goto error;
} }
pdata = NULL; pdata = NULL;
@@ -101,23 +107,24 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
while ((ch = getc(f)) != EOF) { while ((ch = getc(f)) != EOF) {
/* Do not let the server die due to memory exhaustion. */ /* Do not let the server die due to memory exhaustion. */
if ((new_pdata = realloc(pdata, psize + 2)) == NULL) { if ((new_pdata = realloc(pdata, psize + 2)) == NULL) {
cmdq_error(cmdq, "realloc error: %s", strerror(errno)); cmdq_error(item, "realloc error: %s", strerror(errno));
goto error; goto error;
} }
pdata = new_pdata; pdata = new_pdata;
pdata[psize++] = ch; pdata[psize++] = ch;
} }
if (ferror(f)) { if (ferror(f)) {
cmdq_error(cmdq, "%s: read error", resolved); cmdq_error(item, "%s: read error", file);
goto error; goto error;
} }
if (pdata != NULL) if (pdata != NULL)
pdata[psize] = '\0'; pdata[psize] = '\0';
fclose(f); fclose(f);
free(file);
if (paste_set(pdata, psize, bufname, &cause) != 0) { if (paste_set(pdata, psize, bufname, &cause) != 0) {
cmdq_error(cmdq, "%s", cause); cmdq_error(item, "%s", cause);
free(pdata); free(pdata);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@@ -129,15 +136,16 @@ error:
free(pdata); free(pdata);
if (f != NULL) if (f != NULL)
fclose(f); fclose(f);
free(file);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
void static void
cmd_load_buffer_callback(struct client *c, int closed, void *data) cmd_load_buffer_callback(struct client *c, int closed, void *data)
{ {
const char *bufname = data; struct cmd_load_buffer_data *cdata = data;
char *pdata, *cause, *saved; char *pdata, *cause, *saved;
size_t psize; size_t psize;
if (!closed) if (!closed)
return; return;
@@ -145,7 +153,7 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
server_client_unref(c); server_client_unref(c);
if (c->flags & CLIENT_DEAD) if (c->flags & CLIENT_DEAD)
return; goto out;
psize = EVBUFFER_LENGTH(c->stdin_data); psize = EVBUFFER_LENGTH(c->stdin_data);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) if (psize == 0 || (pdata = malloc(psize + 1)) == NULL)
@@ -155,7 +163,7 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
pdata[psize] = '\0'; pdata[psize] = '\0';
evbuffer_drain(c->stdin_data, psize); evbuffer_drain(c->stdin_data, psize);
if (paste_set(pdata, psize, bufname, &cause) != 0) { if (paste_set(pdata, psize, cdata->bufname, &cause) != 0) {
/* No context so can't use server_client_msg_error. */ /* No context so can't use server_client_msg_error. */
if (~c->flags & CLIENT_UTF8) { if (~c->flags & CLIENT_UTF8) {
saved = cause; saved = cause;
@@ -167,7 +175,9 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
free(pdata); free(pdata);
free(cause); free(cause);
} }
out: out:
cmdq_continue(c->cmdq); cmdq_continue(cdata->item);
free(cdata->bufname);
free(cdata);
} }

View File

@@ -24,7 +24,7 @@
* Lock commands. * Lock commands.
*/ */
enum cmd_retval cmd_lock_server_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_lock_server_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_lock_server_entry = { const struct cmd_entry cmd_lock_server_entry = {
.name = "lock-server", .name = "lock-server",
@@ -33,7 +33,7 @@ const struct cmd_entry cmd_lock_server_entry = {
.args = { "", 0, 0 }, .args = { "", 0, 0 },
.usage = "", .usage = "",
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec .exec = cmd_lock_server_exec
}; };
@@ -44,9 +44,9 @@ const struct cmd_entry cmd_lock_session_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE, .usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec .exec = cmd_lock_server_exec
}; };
@@ -57,22 +57,25 @@ const struct cmd_entry cmd_lock_client_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE, .usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT, .flags = CMD_AFTERHOOK,
.flags = 0,
.exec = cmd_lock_server_exec .exec = cmd_lock_server_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_lock_server_exec(struct cmd *self, __unused struct cmd_q *cmdq) cmd_lock_server_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args;
struct client *c;
if (self->entry == &cmd_lock_server_entry) if (self->entry == &cmd_lock_server_entry)
server_lock(); server_lock();
else if (self->entry == &cmd_lock_session_entry) else if (self->entry == &cmd_lock_session_entry)
server_lock_session(cmdq->state.tflag.s); server_lock_session(item->target.s);
else else {
server_lock_client(cmdq->state.c); if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
server_lock_client(c);
}
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -26,7 +26,7 @@
* Move a window. * Move a window.
*/ */
enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_move_window_entry = { const struct cmd_entry cmd_move_window_entry = {
.name = "move-window", .name = "move-window",
@@ -35,8 +35,8 @@ const struct cmd_entry cmd_move_window_entry = {
.args = { "adkrs:t:", 0, 0 }, .args = { "adkrs:t:", 0, 0 },
.usage = "[-dkr] " CMD_SRCDST_WINDOW_USAGE, .usage = "[-dkr] " CMD_SRCDST_WINDOW_USAGE,
.sflag = CMD_WINDOW, .source = { 's', CMD_FIND_WINDOW, 0 },
.tflag = CMD_MOVEW_R, /* -t is special */
.flags = 0, .flags = 0,
.exec = cmd_move_window_exec .exec = cmd_move_window_exec
@@ -49,32 +49,42 @@ const struct cmd_entry cmd_link_window_entry = {
.args = { "adks:t:", 0, 0 }, .args = { "adks:t:", 0, 0 },
.usage = "[-dk] " CMD_SRCDST_WINDOW_USAGE, .usage = "[-dk] " CMD_SRCDST_WINDOW_USAGE,
.sflag = CMD_WINDOW, .source = { 's', CMD_FIND_WINDOW, 0 },
.tflag = CMD_WINDOW_INDEX, /* -t is special */
.flags = 0, .flags = 0,
.exec = cmd_move_window_exec .exec = cmd_move_window_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_move_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *src = cmdq->state.sflag.s; const char *tflag = args_get(args, 't');
struct session *dst = cmdq->state.tflag.s; struct session *src;
struct winlink *wl = cmdq->state.sflag.wl; struct session *dst;
struct winlink *wl;
char *cause; char *cause;
int idx = cmdq->state.tflag.idx, kflag, dflag, sflag; int idx, kflag, dflag, sflag;
kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd');
if (args_has(args, 'r')) { if (args_has(args, 'r')) {
session_renumber_windows(dst); if (cmd_find_target(&item->target, item, tflag,
CMD_FIND_SESSION, CMD_FIND_QUIET) != 0)
return (CMD_RETURN_ERROR);
session_renumber_windows(item->target.s);
recalculate_sizes(); recalculate_sizes();
server_status_session(item->target.s);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (cmd_find_target(&item->target, item, tflag, CMD_FIND_WINDOW,
CMD_FIND_WINDOW_INDEX) != 0)
return (CMD_RETURN_ERROR);
src = item->source.s;
dst = item->target.s;
wl = item->source.wl;
idx = item->target.idx;
kflag = args_has(self->args, 'k'); kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd'); dflag = args_has(self->args, 'd');
@@ -87,7 +97,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq)
if (server_link_window(src, wl, dst, idx, kflag, !dflag, if (server_link_window(src, wl, dst, idx, kflag, !dflag,
&cause) != 0) { &cause) != 0) {
cmdq_error(cmdq, "can't link window: %s", cause); cmdq_error(item, "can't link window: %s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

View File

@@ -33,18 +33,18 @@
#define NEW_SESSION_TEMPLATE "#{session_name}:" #define NEW_SESSION_TEMPLATE "#{session_name}:"
enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_new_session_entry = { const struct cmd_entry cmd_new_session_entry = {
.name = "new-session", .name = "new-session",
.alias = "new", .alias = "new",
.args = { "Ac:dDEF:n:Ps:t:x:y:", 0, -1 }, .args = { "Ac:dDEF:n:Ps:t:x:Xy:", 0, -1 },
.usage = "[-AdDEP] [-c start-directory] [-F format] [-n window-name] " .usage = "[-AdDEPX] [-c start-directory] [-F format] [-n window-name] "
"[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] " "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
"[-y height] [command]", "[-y height] [command]",
.tflag = CMD_SESSION_CANFAIL, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_STARTSERVER, .flags = CMD_STARTSERVER,
.exec = cmd_new_session_exec .exec = cmd_new_session_exec
@@ -57,79 +57,94 @@ const struct cmd_entry cmd_has_session_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE, .usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0, .flags = 0,
.exec = cmd_new_session_exec .exec = cmd_new_session_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmdq->client; struct client *c = item->client;
struct session *s, *as; struct session *s, *as, *groupwith;
struct session *groupwith = cmdq->state.tflag.s;
struct window *w;
struct environ *env; struct environ *env;
struct options *oo;
struct termios tio, *tiop; struct termios tio, *tiop;
const char *newname, *target, *update, *errstr, *template; struct session_group *sg;
const char *path, *cwd, *to_free = NULL; const char *errstr, *template, *group, *prefix, *tmp;
char **argv, *cmd, *cause, *cp; char *cause, *cwd = NULL, *cp, *newname = NULL;
int detached, already_attached, idx, argc; int detached, already_attached, is_control = 0;
u_int sx, sy; u_int sx, sy, dsx, dsy;
struct format_tree *ft; struct spawn_context sc;
struct environ_entry *envent; enum cmd_retval retval;
struct cmd_find_state fs;
if (self->entry == &cmd_has_session_entry) { if (self->entry == &cmd_has_session_entry) {
/* /*
* cmd_prepare() will fail if the session cannot be found, * cmd_find_target() will fail if the session cannot be found,
* hence always return success here. * so always return success here.
*/ */
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) { if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) {
cmdq_error(cmdq, "command or window name given with target"); cmdq_error(item, "command or window name given with target");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
newname = args_get(args, 's'); if (args_has(args, 's')) {
if (newname != NULL) { newname = format_single(item, args_get(args, 's'), c, NULL,
NULL, NULL);
if (!session_check_name(newname)) { if (!session_check_name(newname)) {
cmdq_error(cmdq, "bad session name: %s", newname); cmdq_error(item, "bad session name: %s", newname);
return (CMD_RETURN_ERROR); goto fail;
} }
if ((as = session_find(newname)) != NULL) { if ((as = session_find(newname)) != NULL) {
if (args_has(args, 'A')) { if (args_has(args, 'A')) {
/* retval = cmd_attach_session(item,
* This cmdq is now destined for newname, args_has(args, 'D'),
* attach-session. Because attach-session args_has(args, 'X'), 0, NULL,
* will have already been prepared, copy this args_has(args, 'E'));
* session into its tflag so it can be used. free(newname);
*/ return (retval);
cmd_find_from_session(&cmdq->state.tflag, as);
return (cmd_attach_session(cmdq,
args_has(args, 'D'), 0, NULL,
args_has(args, 'E')));
} }
cmdq_error(cmdq, "duplicate session: %s", newname); cmdq_error(item, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR); goto fail;
} }
} }
if ((target = args_get(args, 't')) != NULL) { /* Is this going to be part of a session group? */
group = args_get(args, 't');
if (group != NULL) {
groupwith = item->target.s;
if (groupwith == NULL) { if (groupwith == NULL) {
cmdq_error(cmdq, "no such session: %s", target); if (!session_check_name(group)) {
goto error; cmdq_error(item, "bad group name: %s", group);
} goto fail;
} else }
sg = session_group_find(group);
} else
sg = session_group_contains(groupwith);
if (sg != NULL)
prefix = sg->name;
else if (groupwith != NULL)
prefix = groupwith->name;
else
prefix = group;
} else {
groupwith = NULL; groupwith = NULL;
sg = NULL;
prefix = NULL;
}
/* Set -d if no client. */ /* Set -d if no client. */
detached = args_has(args, 'd'); detached = args_has(args, 'd');
if (c == NULL) if (c == NULL)
detached = 1; detached = 1;
else if (c->flags & CLIENT_CONTROL)
is_control = 1;
/* Is this client already attached? */ /* Is this client already attached? */
already_attached = 0; already_attached = 0;
@@ -137,15 +152,10 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
already_attached = 1; already_attached = 1;
/* Get the new session working directory. */ /* Get the new session working directory. */
if (args_has(args, 'c')) { if ((tmp = args_get(args, 'c')) != NULL)
ft = format_create(cmdq, 0); cwd = format_single(item, tmp, c, NULL, NULL, NULL);
format_defaults(ft, c, NULL, NULL, NULL);
to_free = cwd = format_expand(ft, args_get(args, 'c'));
format_free(ft);
} else if (c != NULL && c->session == NULL && c->cwd != NULL)
cwd = c->cwd;
else else
cwd = "."; cwd = xstrdup(server_client_get_cwd(c, NULL));
/* /*
* If this is a new client, check for nesting and save the termios * If this is a new client, check for nesting and save the termios
@@ -157,10 +167,10 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
* over. * over.
*/ */
if (!detached && !already_attached && c->tty.fd != -1) { if (!detached && !already_attached && c->tty.fd != -1) {
if (server_client_check_nested(cmdq->client)) { if (server_client_check_nested(item->client)) {
cmdq_error(cmdq, "sessions should be nested with care, " cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force"); "unset $TMUX to force");
return (CMD_RETURN_ERROR); goto fail;
} }
if (tcgetattr(c->tty.fd, &tio) != 0) if (tcgetattr(c->tty.fd, &tio) != 0)
fatal("tcgetattr failed"); fatal("tcgetattr failed");
@@ -171,101 +181,118 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
/* Open the terminal if necessary. */ /* Open the terminal if necessary. */
if (!detached && !already_attached) { if (!detached && !already_attached) {
if (server_client_open(c, &cause) != 0) { if (server_client_open(c, &cause) != 0) {
cmdq_error(cmdq, "open terminal failed: %s", cause); cmdq_error(item, "open terminal failed: %s", cause);
free(cause); free(cause);
goto error; goto fail;
}
}
/* Get default session size. */
if (args_has(args, 'x')) {
tmp = args_get(args, 'x');
if (strcmp(tmp, "-") == 0) {
if (c != NULL)
dsx = c->tty.sx;
else
dsx = 80;
} else {
dsx = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
goto fail;
}
}
}
if (args_has(args, 'y')) {
tmp = args_get(args, 'y');
if (strcmp(tmp, "-") == 0) {
if (c != NULL)
dsy = c->tty.sy;
else
dsy = 24;
} else {
dsy = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
goto fail;
}
} }
} }
/* Find new session size. */ /* Find new session size. */
if (c != NULL) { if (!detached && !is_control) {
sx = c->tty.sx; sx = c->tty.sx;
sy = c->tty.sy; sy = c->tty.sy;
if (sy > 0 && options_get_number(global_s_options, "status"))
sy--;
} else { } else {
sx = 80; tmp = options_get_string(global_s_options, "default-size");
sy = 24; if (sscanf(tmp, "%ux%u", &sx, &sy) != 2) {
} sx = 80;
if (detached && args_has(args, 'x')) { sy = 24;
sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(cmdq, "width %s", errstr);
goto error;
} }
if (args_has(args, 'x'))
sx = dsx;
if (args_has(args, 'y'))
sy = dsy;
} }
if (detached && args_has(args, 'y')) {
sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(cmdq, "height %s", errstr);
goto error;
}
}
if (sy > 0 && options_get_number(global_s_options, "status"))
sy--;
if (sx == 0) if (sx == 0)
sx = 1; sx = 1;
if (sy == 0) if (sy == 0)
sy = 1; sy = 1;
/* Figure out the command for the new window. */
argc = -1;
argv = NULL;
if (!args_has(args, 't') && args->argc != 0) {
argc = args->argc;
argv = args->argv;
} else if (groupwith == NULL) {
cmd = options_get_string(global_s_options, "default-command");
if (cmd != NULL && *cmd != '\0') {
argc = 1;
argv = &cmd;
} else {
argc = 0;
argv = NULL;
}
}
path = NULL;
if (c != NULL && c->session == NULL)
envent = environ_find(c->environ, "PATH");
else
envent = environ_find(global_environ, "PATH");
if (envent != NULL)
path = envent->value;
/* Construct the environment. */
env = environ_create();
if (c != NULL && !args_has(args, 'E')) {
update = options_get_string(global_s_options,
"update-environment");
environ_update(update, c->environ, env);
}
/* Create the new session. */ /* Create the new session. */
idx = -1 - options_get_number(global_s_options, "base-index"); oo = options_create(global_s_options);
s = session_create(newname, argc, argv, path, cwd, env, tiop, idx, sx, if (args_has(args, 'x') || args_has(args, 'y')) {
sy, &cause); if (!args_has(args, 'x'))
environ_free(env); dsx = sx;
if (s == NULL) { if (!args_has(args, 'y'))
cmdq_error(cmdq, "create session failed: %s", cause); dsy = sy;
free(cause); options_set_string(oo, "default-size", 0, "%ux%u", dsx, dsy);
goto error;
} }
env = environ_create();
if (c != NULL && !args_has(args, 'E'))
environ_update(global_s_options, c->environ, env);
s = session_create(prefix, newname, cwd, env, oo, tiop);
/* Set the initial window name if one given. */ /* Spawn the initial window. */
if (argc >= 0 && args_has(args, 'n')) { memset(&sc, 0, sizeof sc);
w = s->curw->window; sc.item = item;
window_set_name(w, args_get(args, 'n')); sc.s = s;
options_set_number(w->options, "automatic-rename", 0);
sc.name = args_get(args, 'n');
sc.argc = args->argc;
sc.argv = args->argv;
sc.idx = -1;
sc.cwd = args_get(args, 'c');
sc.flags = 0;
if (spawn_window(&sc, &cause) == NULL) {
session_destroy(s, 0, __func__);
cmdq_error(item, "create window failed: %s", cause);
free(cause);
goto fail;
} }
/* /*
* If a target session is given, this is to be part of a session group, * If a target session is given, this is to be part of a session group,
* so add it to the group and synchronize. * so add it to the group and synchronize.
*/ */
if (groupwith != NULL) { if (group != NULL) {
session_group_add(groupwith, s); if (sg == NULL) {
if (groupwith != NULL) {
sg = session_group_new(groupwith->name);
session_group_add(sg, groupwith);
} else
sg = session_group_new(group);
}
session_group_add(sg, s);
session_group_synchronize_to(s); session_group_synchronize_to(s);
session_select(s, RB_MIN(winlinks, &s->windows)->idx); session_select(s, RB_MIN(winlinks, &s->windows)->idx);
} }
notify_session("session-created", s);
/* /*
* Set the client to the new session. If a command client exists, it is * Set the client to the new session. If a command client exists, it is
@@ -278,9 +305,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
} else if (c->session != NULL) } else if (c->session != NULL)
c->last_session = c->session; c->last_session = c->session;
c->session = s; c->session = s;
server_client_set_key_table(c, NULL); if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c); status_timer_start(c);
notify_attached_session_changed(c); notify_client("client-session-changed", c);
session_update_activity(s, NULL); session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL); gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c); server_redraw_client(c);
@@ -299,26 +328,25 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = NEW_SESSION_TEMPLATE; template = NEW_SESSION_TEMPLATE;
cp = format_single(item, template, c, s, NULL, NULL);
ft = format_create(cmdq, 0); cmdq_print(item, "%s", cp);
format_defaults(ft, c, s, NULL, NULL);
cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp);
free(cp); free(cp);
format_free(ft);
} }
if (!detached) if (!detached) {
cmdq->client_exit = 0; c->flags |= CLIENT_ATTACHED;
cmd_find_from_session(&item->shared->current, s, 0);
}
if (to_free != NULL) cmd_find_from_session(&fs, s, 0);
free((void *)to_free); cmdq_insert_hook(s, item, &fs, "after-new-session");
free(cwd);
free(newname);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
error: fail:
if (to_free != NULL) free(cwd);
free((void *)to_free); free(newname);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

View File

@@ -32,108 +32,74 @@
#define NEW_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" #define NEW_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_new_window_entry = { const struct cmd_entry cmd_new_window_entry = {
.name = "new-window", .name = "new-window",
.alias = "neww", .alias = "neww",
.args = { "ac:dF:kn:Pt:", 0, -1 }, .args = { "ac:de:F:kn:Pt:", 0, -1 },
.usage = "[-adkP] [-c start-directory] [-F format] [-n window-name] " .usage = "[-adkP] [-c start-directory] [-e environment] [-F format] "
CMD_TARGET_WINDOW_USAGE " [command]", "[-n window-name] " CMD_TARGET_WINDOW_USAGE " [command]",
.tflag = CMD_WINDOW_INDEX, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
.flags = 0, .flags = 0,
.exec = cmd_new_window_exec .exec = cmd_new_window_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s = cmdq->state.tflag.s; struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = cmdq->state.tflag.wl; struct spawn_context sc;
struct client *c = cmdq->state.c; struct client *c = cmd_find_client(item, NULL, 1);
int idx = cmdq->state.tflag.idx; struct session *s = item->target.s;
const char *cmd, *path, *template, *cwd, *to_free; struct winlink *wl = item->target.wl;
char **argv, *cause, *cp; int idx = item->target.idx;
int argc, detached; struct winlink *new_wl;
struct format_tree *ft; char *cause = NULL, *cp;
struct environ_entry *envent; const char *template, *add;
struct cmd_find_state fs;
struct args_value *value;
if (args_has(args, 'a')) { if (args_has(args, 'a') && (idx = winlink_shuffle_up(s, wl)) == -1) {
if ((idx = winlink_shuffle_up(s, wl)) == -1) { cmdq_error(item, "couldn't get a window index");
cmdq_error(cmdq, "no free window indexes"); return (CMD_RETURN_ERROR);
return (CMD_RETURN_ERROR);
}
}
detached = args_has(args, 'd');
if (args->argc == 0) {
cmd = options_get_string(s->options, "default-command");
if (cmd != NULL && *cmd != '\0') {
argc = 1;
argv = (char **)&cmd;
} else {
argc = 0;
argv = NULL;
}
} else {
argc = args->argc;
argv = args->argv;
} }
path = NULL; memset(&sc, 0, sizeof sc);
if (cmdq->client != NULL && cmdq->client->session == NULL) sc.item = item;
envent = environ_find(cmdq->client->environ, "PATH"); sc.s = s;
else
envent = environ_find(s->environ, "PATH");
if (envent != NULL)
path = envent->value;
to_free = NULL; sc.name = args_get(args, 'n');
if (args_has(args, 'c')) { sc.argc = args->argc;
ft = format_create(cmdq, 0); sc.argv = args->argv;
format_defaults(ft, c, s, NULL, NULL); sc.environ = environ_create();
cwd = to_free = format_expand(ft, args_get(args, 'c'));
format_free(ft);
} else if (cmdq->client != NULL && cmdq->client->session == NULL)
cwd = cmdq->client->cwd;
else
cwd = s->cwd;
wl = NULL; add = args_first_value(args, 'e', &value);
if (idx != -1) while (add != NULL) {
wl = winlink_find_by_index(&s->windows, idx); environ_put(sc.environ, add);
if (wl != NULL && args_has(args, 'k')) { add = args_next_value(&value);
/*
* Can't use session_detach as it will destroy session if this
* makes it empty.
*/
notify_window_unlinked(s, wl->window);
wl->flags &= ~WINLINK_ALERTFLAGS;
winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl);
/* Force select/redraw if current. */
if (wl == s->curw) {
detached = 0;
s->curw = NULL;
}
} }
if (idx == -1) sc.idx = idx;
idx = -1 - options_get_number(s->options, "base-index"); sc.cwd = args_get(args, 'c');
wl = session_new(s, args_get(args, 'n'), argc, argv, path, cwd, idx,
&cause); sc.flags = 0;
if (wl == NULL) { if (args_has(args, 'd'))
cmdq_error(cmdq, "create window failed: %s", cause); sc.flags |= SPAWN_DETACHED;
if (args_has(args, 'k'))
sc.flags |= SPAWN_KILL;
if ((new_wl = spawn_window(&sc, &cause)) == NULL) {
cmdq_error(item, "create window failed: %s", cause);
free(cause); free(cause);
goto error; return (CMD_RETURN_ERROR);
} }
if (!detached) { if (!args_has(args, 'd') || new_wl == s->curw) {
session_select(s, wl->idx); cmd_find_from_winlink(current, new_wl, 0);
server_redraw_session_group(s); server_redraw_session_group(s);
} else } else
server_status_session_group(s); server_status_session_group(s);
@@ -141,23 +107,14 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = NEW_WINDOW_TEMPLATE; template = NEW_WINDOW_TEMPLATE;
cp = format_single(item, template, c, s, new_wl, NULL);
ft = format_create(cmdq, 0); cmdq_print(item, "%s", cp);
format_defaults(ft, c, s, wl, NULL);
cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp);
free(cp); free(cp);
format_free(ft);
} }
if (to_free != NULL) cmd_find_from_winlink(&fs, new_wl, 0);
free((void *)to_free); cmdq_insert_hook(s, item, &fs, "after-new-window");
return (CMD_RETURN_NORMAL);
error: environ_free(sc.environ);
if (to_free != NULL) return (CMD_RETURN_NORMAL);
free((void *)to_free);
return (CMD_RETURN_ERROR);
} }

1548
cmd-parse.y Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -27,10 +27,7 @@
* Paste paste buffer if present. * Paste paste buffer if present.
*/ */
enum cmd_retval cmd_paste_buffer_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_paste_buffer_exec(struct cmd *, struct cmdq_item *);
void cmd_paste_buffer_filter(struct window_pane *,
const char *, size_t, const char *, int);
const struct cmd_entry cmd_paste_buffer_entry = { const struct cmd_entry cmd_paste_buffer_entry = {
.name = "paste-buffer", .name = "paste-buffer",
@@ -40,17 +37,17 @@ const struct cmd_entry cmd_paste_buffer_entry = {
.usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " " .usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " "
CMD_TARGET_PANE_USAGE, CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_paste_buffer_exec .exec = cmd_paste_buffer_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq) cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp = cmdq->state.tflag.wp; struct window_pane *wp = item->target.wp;
struct paste_buffer *pb; struct paste_buffer *pb;
const char *sepstr, *bufname, *bufdata, *bufend, *line; const char *sepstr, *bufname, *bufdata, *bufend, *line;
size_t seplen, bufsize; size_t seplen, bufsize;
@@ -65,7 +62,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
else { else {
pb = paste_get_name(bufname); pb = paste_get_name(bufname);
if (pb == NULL) { if (pb == NULL) {
cmdq_error(cmdq, "no buffer %s", bufname); cmdq_error(item, "no buffer %s", bufname);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }

View File

@@ -21,6 +21,7 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
@@ -32,34 +33,37 @@
* Open pipe to redirect pane output. If already open, close first. * Open pipe to redirect pane output. If already open, close first.
*/ */
enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmdq_item *);
void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *); static void cmd_pipe_pane_read_callback(struct bufferevent *, void *);
static void cmd_pipe_pane_write_callback(struct bufferevent *, void *);
static void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *);
const struct cmd_entry cmd_pipe_pane_entry = { const struct cmd_entry cmd_pipe_pane_entry = {
.name = "pipe-pane", .name = "pipe-pane",
.alias = "pipep", .alias = "pipep",
.args = { "ot:", 0, 1 }, .args = { "IOot:", 0, 1 },
.usage = "[-o] " CMD_TARGET_PANE_USAGE " [command]", .usage = "[-IOo] " CMD_TARGET_PANE_USAGE " [command]",
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_pipe_pane_exec .exec = cmd_pipe_pane_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmdq->state.c; struct client *c = cmd_find_client(item, NULL, 1);
struct window_pane *wp = cmdq->state.tflag.wp; struct window_pane *wp = item->target.wp;
struct session *s = cmdq->state.tflag.s; struct session *s = item->target.s;
struct winlink *wl = cmdq->state.tflag.wl; struct winlink *wl = item->target.wl;
char *cmd; char *cmd;
int old_fd, pipe_fd[2], null_fd; int old_fd, pipe_fd[2], null_fd, in, out;
struct format_tree *ft; struct format_tree *ft;
sigset_t set, oldset;
/* Destroy the old pipe. */ /* Destroy the old pipe. */
old_fd = wp->pipe_fd; old_fd = wp->pipe_fd;
@@ -67,6 +71,11 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
bufferevent_free(wp->pipe_event); bufferevent_free(wp->pipe_event);
close(wp->pipe_fd); close(wp->pipe_fd);
wp->pipe_fd = -1; wp->pipe_fd = -1;
if (window_pane_destroy_ready(wp)) {
server_destroy_pane(wp, 1);
return (CMD_RETURN_NORMAL);
}
} }
/* If no pipe command, that is enough. */ /* If no pipe command, that is enough. */
@@ -82,72 +91,135 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(self->args, 'o') && old_fd != -1) if (args_has(self->args, 'o') && old_fd != -1)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
/* What do we want to do? Neither -I or -O is -O. */
if (args_has(self->args, 'I')) {
in = 1;
out = args_has(self->args, 'O');
} else {
in = 0;
out = 1;
}
/* Open the new pipe. */ /* Open the new pipe. */
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) { if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) {
cmdq_error(cmdq, "socketpair error: %s", strerror(errno)); cmdq_error(item, "socketpair error: %s", strerror(errno));
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
/* Expand the command. */ /* Expand the command. */
ft = format_create(cmdq, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, c, s, wl, wp); format_defaults(ft, c, s, wl, wp);
cmd = format_expand_time(ft, args->argv[0], time(NULL)); cmd = format_expand_time(ft, args->argv[0]);
format_free(ft); format_free(ft);
/* Fork the child. */ /* Fork the child. */
sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, &oldset);
switch (fork()) { switch (fork()) {
case -1: case -1:
cmdq_error(cmdq, "fork error: %s", strerror(errno)); sigprocmask(SIG_SETMASK, &oldset, NULL);
cmdq_error(item, "fork error: %s", strerror(errno));
free(cmd); free(cmd);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
case 0: case 0:
/* Child process. */ /* Child process. */
proc_clear_signals(server_proc, 1);
sigprocmask(SIG_SETMASK, &oldset, NULL);
close(pipe_fd[0]); close(pipe_fd[0]);
clear_signals(1);
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
_exit(1);
if (pipe_fd[1] != STDIN_FILENO)
close(pipe_fd[1]);
null_fd = open(_PATH_DEVNULL, O_WRONLY, 0); null_fd = open(_PATH_DEVNULL, O_WRONLY, 0);
if (dup2(null_fd, STDOUT_FILENO) == -1) if (out) {
_exit(1); if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
_exit(1);
} else {
if (dup2(null_fd, STDIN_FILENO) == -1)
_exit(1);
}
if (in) {
if (dup2(pipe_fd[1], STDOUT_FILENO) == -1)
_exit(1);
if (pipe_fd[1] != STDOUT_FILENO)
close(pipe_fd[1]);
} else {
if (dup2(null_fd, STDOUT_FILENO) == -1)
_exit(1);
}
if (dup2(null_fd, STDERR_FILENO) == -1) if (dup2(null_fd, STDERR_FILENO) == -1)
_exit(1); _exit(1);
if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO)
close(null_fd);
closefrom(STDERR_FILENO + 1); closefrom(STDERR_FILENO + 1);
execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
_exit(1); _exit(1);
default: default:
/* Parent process. */ /* Parent process. */
sigprocmask(SIG_SETMASK, &oldset, NULL);
close(pipe_fd[1]); close(pipe_fd[1]);
wp->pipe_fd = pipe_fd[0]; wp->pipe_fd = pipe_fd[0];
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); if (wp->fd != -1)
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
wp->pipe_event = bufferevent_new(wp->pipe_fd, else
NULL, NULL, cmd_pipe_pane_error_callback, wp); wp->pipe_off = 0;
bufferevent_enable(wp->pipe_event, EV_WRITE);
setblocking(wp->pipe_fd, 0); setblocking(wp->pipe_fd, 0);
wp->pipe_event = bufferevent_new(wp->pipe_fd,
cmd_pipe_pane_read_callback,
cmd_pipe_pane_write_callback,
cmd_pipe_pane_error_callback,
wp);
if (wp->pipe_event == NULL)
fatalx("out of memory");
if (out)
bufferevent_enable(wp->pipe_event, EV_WRITE);
if (in)
bufferevent_enable(wp->pipe_event, EV_READ);
free(cmd); free(cmd);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
} }
void static void
cmd_pipe_pane_read_callback(__unused struct bufferevent *bufev, void *data)
{
struct window_pane *wp = data;
struct evbuffer *evb = wp->pipe_event->input;
size_t available;
available = EVBUFFER_LENGTH(evb);
log_debug("%%%u pipe read %zu", wp->id, available);
bufferevent_write(wp->event, EVBUFFER_DATA(evb), available);
evbuffer_drain(evb, available);
if (window_pane_destroy_ready(wp))
server_destroy_pane(wp, 1);
}
static void
cmd_pipe_pane_write_callback(__unused struct bufferevent *bufev, void *data)
{
struct window_pane *wp = data;
log_debug("%%%u pipe empty", wp->id);
if (window_pane_destroy_ready(wp))
server_destroy_pane(wp, 1);
}
static void
cmd_pipe_pane_error_callback(__unused struct bufferevent *bufev, cmd_pipe_pane_error_callback(__unused struct bufferevent *bufev,
__unused short what, void *data) __unused short what, void *data)
{ {
struct window_pane *wp = data; struct window_pane *wp = data;
log_debug("%%%u pipe error", wp->id);
bufferevent_free(wp->pipe_event); bufferevent_free(wp->pipe_event);
close(wp->pipe_fd); close(wp->pipe_fd);
wp->pipe_fd = -1; wp->pipe_fd = -1;
if (window_pane_destroy_ready(wp))
server_destroy_pane(wp, 1);
} }

View File

@@ -25,54 +25,475 @@
#include "tmux.h" #include "tmux.h"
static enum cmd_retval cmdq_continue_one(struct cmd_q *); /* Global command queue. */
static struct cmdq_list global_queue = TAILQ_HEAD_INITIALIZER(global_queue);
/* Create new command queue. */ /* Get command queue name. */
struct cmd_q * static const char *
cmdq_new(struct client *c) cmdq_name(struct client *c)
{ {
struct cmd_q *cmdq; static char s[256];
cmdq = xcalloc(1, sizeof *cmdq); if (c == NULL)
cmdq->references = 1; return ("<global>");
cmdq->flags = 0; if (c->name != NULL)
xsnprintf(s, sizeof s, "<%s>", c->name);
cmdq->client = c; else
cmdq->client_exit = -1; xsnprintf(s, sizeof s, "<%p>", c);
return (s);
TAILQ_INIT(&cmdq->queue);
cmdq->item = NULL;
cmdq->cmd = NULL;
cmd_find_clear_state(&cmdq->current, NULL, 0);
cmdq->parent = NULL;
return (cmdq);
} }
/* Free command queue */ /* Get command queue from client. */
int static struct cmdq_list *
cmdq_free(struct cmd_q *cmdq) cmdq_get(struct client *c)
{ {
if (--cmdq->references != 0) { if (c == NULL)
if (cmdq->flags & CMD_Q_DEAD) return (&global_queue);
return (1); return (&c->queue);
}
/* Append an item. */
void
cmdq_append(struct client *c, struct cmdq_item *item)
{
struct cmdq_list *queue = cmdq_get(c);
struct cmdq_item *next;
do {
next = item->next;
item->next = NULL;
if (c != NULL)
c->references++;
item->client = c;
item->queue = queue;
TAILQ_INSERT_TAIL(queue, item, entry);
log_debug("%s %s: %s", __func__, cmdq_name(c), item->name);
item = next;
} while (item != NULL);
}
/* Insert an item. */
void
cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
{
struct client *c = after->client;
struct cmdq_list *queue = after->queue;
struct cmdq_item *next;
do {
next = item->next;
item->next = after->next;
after->next = item;
if (c != NULL)
c->references++;
item->client = c;
item->queue = queue;
TAILQ_INSERT_AFTER(queue, after, item, entry);
log_debug("%s %s: %s after %s", __func__, cmdq_name(c),
item->name, after->name);
after = item;
item = next;
} while (item != NULL);
}
/* Insert a hook. */
void
cmdq_insert_hook(struct session *s, struct cmdq_item *item,
struct cmd_find_state *fs, const char *fmt, ...)
{
struct options *oo;
va_list ap;
char *name;
struct cmdq_item *new_item;
struct options_entry *o;
struct options_array_item *a;
struct cmd_list *cmdlist;
if (item->flags & CMDQ_NOHOOKS)
return;
if (s == NULL)
oo = global_s_options;
else
oo = s->options;
va_start(ap, fmt);
xvasprintf(&name, fmt, ap);
va_end(ap);
o = options_get(oo, name);
if (o == NULL) {
free(name);
return;
}
log_debug("running hook %s (parent %p)", name, item);
a = options_array_first(o);
while (a != NULL) {
cmdlist = options_array_item_value(a)->cmdlist;
if (cmdlist == NULL) {
a = options_array_next(a);
continue;
}
new_item = cmdq_get_command(cmdlist, fs, NULL, CMDQ_NOHOOKS);
cmdq_format(new_item, "hook", "%s", name);
if (item != NULL) {
cmdq_insert_after(item, new_item);
item = new_item;
} else
cmdq_append(NULL, new_item);
a = options_array_next(a);
}
free(name);
}
/* Continue processing command queue. */
void
cmdq_continue(struct cmdq_item *item)
{
item->flags &= ~CMDQ_WAITING;
}
/* Remove an item. */
static void
cmdq_remove(struct cmdq_item *item)
{
if (item->shared != NULL && --item->shared->references == 0) {
if (item->shared->formats != NULL)
format_free(item->shared->formats);
free(item->shared);
}
if (item->client != NULL)
server_client_unref(item->client);
if (item->cmdlist != NULL)
cmd_list_free(item->cmdlist);
TAILQ_REMOVE(item->queue, item, entry);
free(item->name);
free(item);
}
/* Remove all subsequent items that match this item's group. */
static void
cmdq_remove_group(struct cmdq_item *item)
{
struct cmdq_item *this, *next;
if (item->group == 0)
return;
this = TAILQ_NEXT(item, entry);
while (this != NULL) {
next = TAILQ_NEXT(this, entry);
if (this->group == item->group)
cmdq_remove(this);
this = next;
}
}
/* Get a command for the command queue. */
struct cmdq_item *
cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
struct mouse_event *m, int flags)
{
struct cmdq_item *item, *first = NULL, *last = NULL;
struct cmd *cmd;
struct cmdq_shared *shared = NULL;
u_int group = 0;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if (cmd->group != group) {
shared = xcalloc(1, sizeof *shared);
if (current != NULL)
cmd_find_copy_state(&shared->current, current);
else
cmd_find_clear_state(&shared->current, 0);
if (m != NULL)
memcpy(&shared->mouse, m, sizeof shared->mouse);
group = cmd->group;
}
item = xcalloc(1, sizeof *item);
xasprintf(&item->name, "[%s/%p]", cmd->entry->name, item);
item->type = CMDQ_COMMAND;
item->group = cmd->group;
item->flags = flags;
item->shared = shared;
item->cmdlist = cmdlist;
item->cmd = cmd;
log_debug("%s: %s group %u", __func__, item->name, item->group);
shared->references++;
cmdlist->references++;
if (first == NULL)
first = item;
if (last != NULL)
last->next = item;
last = item;
}
return (first);
}
/* Fill in flag for a command. */
static enum cmd_retval
cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs,
const struct cmd_entry_flag *flag)
{
const char *value;
if (flag->flag == 0) {
cmd_find_clear_state(fs, 0);
return (CMD_RETURN_NORMAL);
}
value = args_get(item->cmd->args, flag->flag);
if (cmd_find_target(fs, item, value, flag->type, flag->flags) != 0) {
cmd_find_clear_state(fs, 0);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
/* Fire command on command queue. */
static enum cmd_retval
cmdq_fire_command(struct cmdq_item *item)
{
struct client *c = item->client;
const char *name = cmdq_name(c);
struct cmdq_shared *shared = item->shared;
struct cmd *cmd = item->cmd;
const struct cmd_entry *entry = cmd->entry;
enum cmd_retval retval;
struct cmd_find_state *fsp, fs;
int flags;
char *tmp;
if (log_get_level() > 1) {
tmp = cmd_print(cmd);
log_debug("%s %s: (%u) %s", __func__, name, item->group, tmp);
free(tmp);
}
flags = !!(shared->flags & CMDQ_SHARED_CONTROL);
cmdq_guard(item, "begin", flags);
if (item->client == NULL)
item->client = cmd_find_client(item, NULL, 1);
retval = cmdq_find_flag(item, &item->source, &entry->source);
if (retval == CMD_RETURN_ERROR)
goto out;
retval = cmdq_find_flag(item, &item->target, &entry->target);
if (retval == CMD_RETURN_ERROR)
goto out;
retval = entry->exec(cmd, item);
if (retval == CMD_RETURN_ERROR)
goto out;
if (entry->flags & CMD_AFTERHOOK) {
if (cmd_find_valid_state(&item->target))
fsp = &item->target;
else if (cmd_find_valid_state(&item->shared->current))
fsp = &item->shared->current;
else if (cmd_find_from_client(&fs, item->client, 0) == 0)
fsp = &fs;
else
goto out;
cmdq_insert_hook(fsp->s, item, fsp, "after-%s", entry->name);
}
out:
item->client = c;
if (retval == CMD_RETURN_ERROR)
cmdq_guard(item, "error", flags);
else
cmdq_guard(item, "end", flags);
return (retval);
}
/* Get a callback for the command queue. */
struct cmdq_item *
cmdq_get_callback1(const char *name, cmdq_cb cb, void *data)
{
struct cmdq_item *item;
item = xcalloc(1, sizeof *item);
xasprintf(&item->name, "[%s/%p]", name, item);
item->type = CMDQ_CALLBACK;
item->group = 0;
item->flags = 0;
item->cb = cb;
item->data = data;
return (item);
}
/* Generic error callback. */
static enum cmd_retval
cmdq_error_callback(struct cmdq_item *item, void *data)
{
char *error = data;
cmdq_error(item, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
/* Get an error callback for the command queue. */
struct cmdq_item *
cmdq_get_error(const char *error)
{
return (cmdq_get_callback(cmdq_error_callback, xstrdup(error)));
}
/* Fire callback on callback queue. */
static enum cmd_retval
cmdq_fire_callback(struct cmdq_item *item)
{
return (item->cb(item, item->data));
}
/* Add a format to command queue. */
void
cmdq_format(struct cmdq_item *item, const char *key, const char *fmt, ...)
{
struct cmdq_shared *shared = item->shared;
va_list ap;
char *value;
va_start(ap, fmt);
xvasprintf(&value, fmt, ap);
va_end(ap);
if (shared->formats == NULL)
shared->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
format_add(shared->formats, key, "%s", value);
free(value);
}
/* Process next item on command queue. */
u_int
cmdq_next(struct client *c)
{
struct cmdq_list *queue = cmdq_get(c);
const char *name = cmdq_name(c);
struct cmdq_item *item;
enum cmd_retval retval;
u_int items = 0;
static u_int number;
if (TAILQ_EMPTY(queue)) {
log_debug("%s %s: empty", __func__, name);
return (0);
}
if (TAILQ_FIRST(queue)->flags & CMDQ_WAITING) {
log_debug("%s %s: waiting", __func__, name);
return (0); return (0);
} }
cmdq_flush(cmdq); log_debug("%s %s: enter", __func__, name);
free(cmdq); for (;;) {
return (1); item = TAILQ_FIRST(queue);
if (item == NULL)
break;
log_debug("%s %s: %s (%d), flags %x", __func__, name,
item->name, item->type, item->flags);
/*
* Any item with the waiting flag set waits until an external
* event clears the flag (for example, a job - look at
* run-shell).
*/
if (item->flags & CMDQ_WAITING)
goto waiting;
/*
* Items are only fired once, once the fired flag is set, a
* waiting flag can only be cleared by an external event.
*/
if (~item->flags & CMDQ_FIRED) {
item->time = time(NULL);
item->number = ++number;
switch (item->type) {
case CMDQ_COMMAND:
retval = cmdq_fire_command(item);
/*
* If a command returns an error, remove any
* subsequent commands in the same group.
*/
if (retval == CMD_RETURN_ERROR)
cmdq_remove_group(item);
break;
case CMDQ_CALLBACK:
retval = cmdq_fire_callback(item);
break;
default:
retval = CMD_RETURN_ERROR;
break;
}
item->flags |= CMDQ_FIRED;
if (retval == CMD_RETURN_WAIT) {
item->flags |= CMDQ_WAITING;
goto waiting;
}
items++;
}
cmdq_remove(item);
}
log_debug("%s %s: exit (empty)", __func__, name);
return (items);
waiting:
log_debug("%s %s: exit (wait)", __func__, name);
return (items);
}
/* Print a guard line. */
void
cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
{
struct client *c = item->client;
if (c == NULL || !(c->flags & CLIENT_CONTROL))
return;
evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
(long)item->time, item->number, flags);
server_client_push_stdout(c);
} }
/* Show message from command. */ /* Show message from command. */
void void
cmdq_print(struct cmd_q *cmdq, const char *fmt, ...) cmdq_print(struct cmdq_item *item, const char *fmt, ...)
{ {
struct client *c = cmdq->client; struct client *c = item->client;
struct window *w; struct window_pane *wp;
va_list ap; struct window_mode_entry *wme;
char *tmp, *msg; va_list ap;
char *tmp, *msg;
va_start(ap, fmt); va_start(ap, fmt);
@@ -90,13 +511,11 @@ cmdq_print(struct cmd_q *cmdq, const char *fmt, ...)
evbuffer_add(c->stdout_data, "\n", 1); evbuffer_add(c->stdout_data, "\n", 1);
server_client_push_stdout(c); server_client_push_stdout(c);
} else { } else {
w = c->session->curw->window; wp = c->session->curw->window->active;
if (w->active->mode != &window_copy_mode) { wme = TAILQ_FIRST(&wp->modes);
window_pane_reset_mode(w->active); if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(w->active, &window_copy_mode); window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
window_copy_init_for_output(w->active); window_copy_vadd(wp, fmt, ap);
}
window_copy_vadd(w->active, fmt, ap);
} }
va_end(ap); va_end(ap);
@@ -104,10 +523,10 @@ cmdq_print(struct cmd_q *cmdq, const char *fmt, ...)
/* Show error from command. */ /* Show error from command. */
void void
cmdq_error(struct cmd_q *cmdq, const char *fmt, ...) cmdq_error(struct cmdq_item *item, const char *fmt, ...)
{ {
struct client *c = cmdq->client; struct client *c = item->client;
struct cmd *cmd = cmdq->cmd; struct cmd *cmd = item->cmd;
va_list ap; va_list ap;
char *msg; char *msg;
size_t msglen; size_t msglen;
@@ -117,6 +536,8 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...)
msglen = xvasprintf(&msg, fmt, ap); msglen = xvasprintf(&msg, fmt, ap);
va_end(ap); va_end(ap);
log_debug("%s: %s", __func__, msg);
if (c == NULL) if (c == NULL)
cfg_add_cause("%s:%u: %s", cmd->file, cmd->line, msg); cfg_add_cause("%s:%u: %s", cmd->file, cmd->line, msg);
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) { else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
@@ -137,198 +558,3 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...)
free(msg); free(msg);
} }
/* Print a guard line. */
void
cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags)
{
struct client *c = cmdq->client;
if (c == NULL || !(c->flags & CLIENT_CONTROL))
return;
evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
(long) cmdq->time, cmdq->number, flags);
server_client_push_stdout(c);
}
/* Add command list to queue and begin processing if needed. */
void
cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m)
{
cmdq_append(cmdq, cmdlist, m);
if (cmdq->item == NULL) {
cmdq->cmd = NULL;
cmdq_continue(cmdq);
}
}
/* Add command list to queue. */
void
cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m)
{
struct cmd_q_item *item;
item = xcalloc(1, sizeof *item);
item->cmdlist = cmdlist;
TAILQ_INSERT_TAIL(&cmdq->queue, item, qentry);
cmdlist->references++;
if (m != NULL)
memcpy(&item->mouse, m, sizeof item->mouse);
else
item->mouse.valid = 0;
}
/* Process one command. */
static enum cmd_retval
cmdq_continue_one(struct cmd_q *cmdq)
{
struct cmd *cmd = cmdq->cmd;
const char *name = cmd->entry->name;
struct session *s;
struct hooks *hooks;
enum cmd_retval retval;
char *tmp;
int flags = !!(cmd->flags & CMD_CONTROL);
tmp = cmd_print(cmd);
log_debug("cmdq %p: %s", cmdq, tmp);
free(tmp);
cmdq->time = time(NULL);
cmdq->number++;
if (~cmdq->flags & CMD_Q_REENTRY)
cmdq_guard(cmdq, "begin", flags);
if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)
goto error;
if (~cmdq->flags & CMD_Q_NOHOOKS) {
s = NULL;
if (cmdq->state.tflag.s != NULL)
s = cmdq->state.tflag.s;
else if (cmdq->state.sflag.s != NULL)
s = cmdq->state.sflag.s;
else if (cmdq->state.c != NULL)
s = cmdq->state.c->session;
if (s != NULL)
hooks = s->hooks;
else
hooks = global_hooks;
if (~cmdq->flags & CMD_Q_REENTRY) {
cmdq->flags |= CMD_Q_REENTRY;
if (hooks_wait(hooks, cmdq, NULL,
"before-%s", name) == 0)
return (CMD_RETURN_WAIT);
if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)
goto error;
}
} else
hooks = NULL;
cmdq->flags &= ~CMD_Q_REENTRY;
retval = cmd->entry->exec(cmd, cmdq);
if (retval == CMD_RETURN_ERROR)
goto error;
if (hooks != NULL && hooks_wait(hooks, cmdq, NULL,
"after-%s", name) == 0)
retval = CMD_RETURN_WAIT;
cmdq_guard(cmdq, "end", flags);
return (retval);
error:
cmdq_guard(cmdq, "error", flags);
cmdq->flags &= ~CMD_Q_REENTRY;
return (CMD_RETURN_ERROR);
}
/* Continue processing command queue. Returns 1 if finishes empty. */
int
cmdq_continue(struct cmd_q *cmdq)
{
struct client *c = cmdq->client;
struct cmd_q_item *next;
enum cmd_retval retval;
int empty;
cmdq->references++;
notify_disable();
log_debug("continuing cmdq %p: flags %#x, client %p", cmdq, cmdq->flags,
c);
empty = TAILQ_EMPTY(&cmdq->queue);
if (empty)
goto empty;
/*
* If the command isn't in the middle of running hooks (due to
* CMD_RETURN_WAIT), move onto the next command; otherwise, leave the
* state of the queue as it is.
*/
if (~cmdq->flags & CMD_Q_REENTRY) {
if (cmdq->item == NULL) {
cmdq->item = TAILQ_FIRST(&cmdq->queue);
cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
} else
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
}
do {
while (cmdq->cmd != NULL) {
retval = cmdq_continue_one(cmdq);
if (retval == CMD_RETURN_ERROR)
break;
if (retval == CMD_RETURN_WAIT)
goto out;
if (retval == CMD_RETURN_STOP) {
cmdq_flush(cmdq);
goto empty;
}
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
}
next = TAILQ_NEXT(cmdq->item, qentry);
TAILQ_REMOVE(&cmdq->queue, cmdq->item, qentry);
cmd_list_free(cmdq->item->cmdlist);
free(cmdq->item);
cmdq->item = next;
if (cmdq->item != NULL)
cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
} while (cmdq->item != NULL);
empty:
if (cmdq->client_exit > 0)
cmdq->client->flags |= CLIENT_EXIT;
if (cmdq->emptyfn != NULL)
cmdq->emptyfn(cmdq);
empty = 1;
out:
notify_enable();
cmdq_free(cmdq);
return (empty);
}
/* Flush command queue. */
void
cmdq_flush(struct cmd_q *cmdq)
{
struct cmd_q_item *item, *item1;
TAILQ_FOREACH_SAFE(item, &cmdq->queue, qentry, item1) {
TAILQ_REMOVE(&cmdq->queue, item, qentry);
cmd_list_free(item->cmdlist);
free(item);
}
cmdq->item = NULL;
}

View File

@@ -18,62 +18,144 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Refresh client. * Refresh client.
*/ */
enum cmd_retval cmd_refresh_client_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_refresh_client_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_refresh_client_entry = { const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client", .name = "refresh-client",
.alias = "refresh", .alias = "refresh",
.args = { "C:St:", 0, 0 }, .args = { "cC:DF:lLRSt:U", 0, 1 },
.usage = "[-S] [-C size] " CMD_TARGET_CLIENT_USAGE, .usage = "[-cDlLRSU] [-C XxY] [-F flags] " CMD_TARGET_CLIENT_USAGE
" [adjustment]",
.tflag = CMD_CLIENT, .flags = CMD_AFTERHOOK,
.flags = 0,
.exec = cmd_refresh_client_exec .exec = cmd_refresh_client_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_refresh_client_exec(struct cmd *self, struct cmd_q *cmdq) cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmdq->state.c; struct client *c;
const char *size; struct tty *tty;
u_int w, h; struct window *w;
const char *size, *errstr;
char *copy, *next, *s;
u_int x, y, adjust;
if (args_has(args, 'C')) { if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
if ((size = args_get(args, 'C')) == NULL) { return (CMD_RETURN_ERROR);
cmdq_error(cmdq, "missing size"); tty = &c->tty;
return (CMD_RETURN_ERROR);
if (args_has(args, 'c') ||
args_has(args, 'L') ||
args_has(args, 'R') ||
args_has(args, 'U') ||
args_has(args, 'D'))
{
if (args->argc == 0)
adjust = 1;
else {
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "adjustment %s", errstr);
return (CMD_RETURN_ERROR);
}
} }
if (sscanf(size, "%u,%u", &w, &h) != 2) {
cmdq_error(cmdq, "bad size argument"); if (args_has(args, 'c'))
return (CMD_RETURN_ERROR); c->pan_window = NULL;
else {
w = c->session->curw->window;
if (c->pan_window != w) {
c->pan_window = w;
c->pan_ox = tty->oox;
c->pan_oy = tty->ooy;
}
if (args_has(args, 'L')) {
if (c->pan_ox > adjust)
c->pan_ox -= adjust;
else
c->pan_ox = 0;
} else if (args_has(args, 'R')) {
c->pan_ox += adjust;
if (c->pan_ox > w->sx - tty->osx)
c->pan_ox = w->sx - tty->osx;
} else if (args_has(args, 'U')) {
if (c->pan_oy > adjust)
c->pan_oy -= adjust;
else
c->pan_oy = 0;
} else if (args_has(args, 'D')) {
c->pan_oy += adjust;
if (c->pan_oy > w->sy - tty->osy)
c->pan_oy = w->sy - tty->osy;
}
} }
if (w < PANE_MINIMUM || w > 5000 || tty_update_client_offset(c);
h < PANE_MINIMUM || h > 5000) { server_redraw_client(c);
cmdq_error(cmdq, "size too small or too big"); return (CMD_RETURN_NORMAL);
return (CMD_RETURN_ERROR); }
}
if (!(c->flags & CLIENT_CONTROL)) { if (args_has(args, 'l')) {
cmdq_error(cmdq, "not a control client"); if (c->session != NULL)
return (CMD_RETURN_ERROR); tty_putcode_ptr2(&c->tty, TTYC_MS, "", "?");
} return (CMD_RETURN_NORMAL);
if (tty_set_size(&c->tty, w, h)) }
if (args_has(args, 'C') || args_has(args, 'F')) {
if (args_has(args, 'C')) {
if (!(c->flags & CLIENT_CONTROL)) {
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}
size = args_get(args, 'C');
if (sscanf(size, "%u,%u", &x, &y) != 2 &&
sscanf(size, "%ux%u", &x, &y) != 2) {
cmdq_error(item, "bad size argument");
return (CMD_RETURN_ERROR);
}
if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
cmdq_error(item, "size too small or too big");
return (CMD_RETURN_ERROR);
}
tty_set_size(&c->tty, x, y);
c->flags |= CLIENT_SIZECHANGED;
recalculate_sizes(); recalculate_sizes();
} else if (args_has(args, 'S')) { }
if (args_has(args, 'F')) {
if (!(c->flags & CLIENT_CONTROL)) {
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}
s = copy = xstrdup(args_get(args, 'F'));
while ((next = strsep(&s, ",")) != NULL) {
/* Unknown flags are ignored. */
if (strcmp(next, "no-output") == 0)
c->flags |= CLIENT_CONTROL_NOOUTPUT;
}
free(copy);
}
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'S')) {
c->flags |= CLIENT_STATUSFORCE; c->flags |= CLIENT_STATUSFORCE;
server_status_client(c); server_status_client(c);
} else { } else {
c->flags |= CLIENT_STATUSFORCE; c->flags |= CLIENT_STATUSFORCE;
server_redraw_client(c); server_redraw_client(c);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -19,6 +19,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -26,7 +27,8 @@
* Change session name. * Change session name.
*/ */
enum cmd_retval cmd_rename_session_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_rename_session_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_rename_session_entry = { const struct cmd_entry cmd_rename_session_entry = {
.name = "rename-session", .name = "rename-session",
@@ -35,36 +37,44 @@ const struct cmd_entry cmd_rename_session_entry = {
.args = { "t:", 1, 1 }, .args = { "t:", 1, 1 },
.usage = CMD_TARGET_SESSION_USAGE " new-name", .usage = CMD_TARGET_SESSION_USAGE " new-name",
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_rename_session_exec .exec = cmd_rename_session_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_rename_session_exec(struct cmd *self, struct cmd_q *cmdq) cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s = cmdq->state.tflag.s; struct client *c = cmd_find_client(item, NULL, 1);
const char *newname; struct session *s = item->target.s;
char *newname;
newname = format_single(item, args->argv[0], c, s, NULL, NULL);
if (strcmp(newname, s->name) == 0) {
free(newname);
return (CMD_RETURN_NORMAL);
}
newname = args->argv[0];
if (!session_check_name(newname)) { if (!session_check_name(newname)) {
cmdq_error(cmdq, "bad session name: %s", newname); cmdq_error(item, "bad session name: %s", newname);
free(newname);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (session_find(newname) != NULL) { if (session_find(newname) != NULL) {
cmdq_error(cmdq, "duplicate session: %s", newname); cmdq_error(item, "duplicate session: %s", newname);
free(newname);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
RB_REMOVE(sessions, &sessions, s); RB_REMOVE(sessions, &sessions, s);
free(s->name); free(s->name);
s->name = xstrdup(newname); s->name = newname;
RB_INSERT(sessions, &sessions, s); RB_INSERT(sessions, &sessions, s);
server_status_session(s); server_status_session(s);
notify_session_renamed(s); notify_session("session-renamed", s);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -26,7 +26,8 @@
* Rename a window. * Rename a window.
*/ */
enum cmd_retval cmd_rename_window_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_rename_window_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_rename_window_entry = { const struct cmd_entry cmd_rename_window_entry = {
.name = "rename-window", .name = "rename-window",
@@ -35,22 +36,27 @@ const struct cmd_entry cmd_rename_window_entry = {
.args = { "t:", 1, 1 }, .args = { "t:", 1, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " new-name", .usage = CMD_TARGET_WINDOW_USAGE " new-name",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_rename_window_exec .exec = cmd_rename_window_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_rename_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = cmdq->state.tflag.wl; struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
char *newname;
window_set_name(wl->window, args->argv[0]); newname = format_single(item, args->argv[0], c, s, wl, NULL);
window_set_name(wl->window, newname);
options_set_number(wl->window->options, "automatic-rename", 0); options_set_number(wl->window->options, "automatic-rename", 0);
server_status_window(wl->window); server_status_window(wl->window);
free(newname);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -26,9 +26,10 @@
* Increase or decrease pane size. * Increase or decrease pane size.
*/ */
enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmdq_item *);
void cmd_resize_pane_mouse_update(struct client *, struct mouse_event *); static void cmd_resize_pane_mouse_update(struct client *,
struct mouse_event *);
const struct cmd_entry cmd_resize_pane_entry = { const struct cmd_entry cmd_resize_pane_entry = {
.name = "resize-pane", .name = "resize-pane",
@@ -38,33 +39,34 @@ const struct cmd_entry cmd_resize_pane_entry = {
.usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " " .usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
"[adjustment]", "[adjustment]",
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_resize_pane_exec .exec = cmd_resize_pane_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp = cmdq->state.tflag.wp; struct cmdq_shared *shared = item->shared;
struct winlink *wl = cmdq->state.tflag.wl; struct window_pane *wp = item->target.wp;
struct winlink *wl = item->target.wl;
struct window *w = wl->window; struct window *w = wl->window;
struct client *c = cmdq->client; struct client *c = item->client;
struct session *s = cmdq->state.tflag.s; struct session *s = item->target.s;
const char *errstr; const char *errstr;
char *cause; char *cause;
u_int adjust; u_int adjust;
int x, y; int x, y;
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
if (cmd_mouse_window(&cmdq->item->mouse, &s) == NULL) if (cmd_mouse_window(&shared->mouse, &s) == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s) if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update; c->tty.mouse_drag_update = cmd_resize_pane_mouse_update;
cmd_resize_pane_mouse_update(c, &cmdq->item->mouse); cmd_resize_pane_mouse_update(c, &shared->mouse);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -84,88 +86,105 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq)
else { else {
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr); adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
cmdq_error(cmdq, "adjustment %s", errstr); cmdq_error(item, "adjustment %s", errstr);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
if (args_has(self->args, 'x')) { if (args_has(args, 'x')) {
x = args_strtonum(self->args, 'x', PANE_MINIMUM, INT_MAX, x = args_strtonum(args, 'x', PANE_MINIMUM, INT_MAX, &cause);
&cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(cmdq, "width %s", cause); cmdq_error(item, "width %s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x); layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
} }
if (args_has(self->args, 'y')) { if (args_has(args, 'y')) {
y = args_strtonum(self->args, 'y', PANE_MINIMUM, INT_MAX, y = args_strtonum(args, 'y', PANE_MINIMUM, INT_MAX, &cause);
&cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(cmdq, "height %s", cause); cmdq_error(item, "height %s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y); layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
} }
if (args_has(self->args, 'L')) if (args_has(args, 'L'))
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust); layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust, 1);
else if (args_has(self->args, 'R')) else if (args_has(args, 'R'))
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust); layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust, 1);
else if (args_has(self->args, 'U')) else if (args_has(args, 'U'))
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust); layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust, 1);
else if (args_has(self->args, 'D')) else if (args_has(args, 'D'))
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust); layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust, 1);
server_redraw_window(wl->window); server_redraw_window(wl->window);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
void static void
cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m) cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m)
{ {
struct winlink *wl; struct winlink *wl;
struct window_pane *wp; struct window *w;
int found; u_int y, ly, x, lx;
u_int y, ly; static const int offsets[][2] = {
{ 0, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
};
struct layout_cell *cells[nitems(offsets)], *lc;
u_int ncells = 0, i, j, resizes = 0;
enum layout_type type;
wl = cmd_mouse_window(m, NULL); wl = cmd_mouse_window(m, NULL);
if (wl == NULL) { if (wl == NULL) {
c->tty.mouse_drag_update = NULL; c->tty.mouse_drag_update = NULL;
return; return;
} }
w = wl->window;
y = m->y; y = m->y + m->oy; x = m->x + m->ox;
if (m->statusat == 0 && y > 0) if (m->statusat == 0 && y >= m->statuslines)
y--; y -= m->statuslines;
else if (m->statusat > 0 && y >= (u_int)m->statusat) else if (m->statusat > 0 && y >= (u_int)m->statusat)
y = m->statusat - 1; y = m->statusat - 1;
ly = m->ly; ly = m->ly + m->oy; lx = m->lx + m->ox;
if (m->statusat == 0 && ly > 0) if (m->statusat == 0 && ly >= m->statuslines)
ly--; ly -= m->statuslines;
else if (m->statusat > 0 && ly >= (u_int)m->statusat) else if (m->statusat > 0 && ly >= (u_int)m->statusat)
ly = m->statusat - 1; ly = m->statusat - 1;
found = 0; for (i = 0; i < nitems(cells); i++) {
TAILQ_FOREACH(wp, &wl->window->panes, entry) { lc = layout_search_by_border(w->layout_root, lx + offsets[i][0],
if (!window_pane_visible(wp)) ly + offsets[i][1]);
if (lc == NULL)
continue; continue;
if (wp->xoff + wp->sx == m->lx && for (j = 0; j < ncells; j++) {
wp->yoff <= 1 + ly && wp->yoff + wp->sy >= ly) { if (cells[j] == lc) {
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, m->x - m->lx); lc = NULL;
found = 1; break;
}
} }
if (wp->yoff + wp->sy == ly && if (lc == NULL)
wp->xoff <= 1 + m->lx && wp->xoff + wp->sx >= m->lx) { continue;
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, y - ly);
found = 1; cells[ncells] = lc;
ncells++;
}
if (ncells == 0)
return;
for (i = 0; i < ncells; i++) {
type = cells[i]->parent->type;
if (y != ly && type == LAYOUT_TOPBOTTOM) {
layout_resize_layout(w, cells[i], type, y - ly, 0);
resizes++;
} else if (x != lx && type == LAYOUT_LEFTRIGHT) {
layout_resize_layout(w, cells[i], type, x - lx, 0);
resizes++;
} }
} }
if (found) if (resizes != 0)
server_redraw_window(wl->window); server_redraw_window(w);
else
c->tty.mouse_drag_update = NULL;
} }

109
cmd-resize-window.c Normal file
View File

@@ -0,0 +1,109 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2018 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Increase or decrease window size.
*/
static enum cmd_retval cmd_resize_window_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_resize_window_entry = {
.name = "resize-window",
.alias = "resizew",
.args = { "aADLRt:Ux:y:", 0, 1 },
.usage = "[-aADLRU] [-x width] [-y height] " CMD_TARGET_WINDOW_USAGE " "
"[adjustment]",
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_resize_window_exec
};
static enum cmd_retval
cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct session *s = item->target.s;
const char *errstr;
char *cause;
u_int adjust, sx, sy;
if (args->argc == 0)
adjust = 1;
else {
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "adjustment %s", errstr);
return (CMD_RETURN_ERROR);
}
}
sx = w->sx;
sy = w->sy;
if (args_has(args, 'x')) {
sx = args_strtonum(args, 'x', WINDOW_MINIMUM, WINDOW_MAXIMUM,
&cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
if (args_has(args, 'y')) {
sy = args_strtonum(args, 'y', WINDOW_MINIMUM, WINDOW_MAXIMUM,
&cause);
if (cause != NULL) {
cmdq_error(item, "height %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
if (args_has(args, 'L')) {
if (sx >= adjust)
sx -= adjust;
} else if (args_has(args, 'R'))
sx += adjust;
else if (args_has(args, 'U')) {
if (sy >= adjust)
sy -= adjust;
} else if (args_has(args, 'D'))
sy += adjust;
if (args_has(args, 'A'))
default_window_size(s, w, &sx, &sy, WINDOW_SIZE_LARGEST);
else if (args_has(args, 'a'))
default_window_size(s, w, &sx, &sy, WINDOW_SIZE_SMALLEST);
options_set_number(w->options, "window-size", WINDOW_SIZE_MANUAL);
resize_window(w, sx, sy);
return (CMD_RETURN_NORMAL);
}

View File

@@ -20,7 +20,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -28,70 +28,69 @@
* Respawn a pane (restart the command). Kill existing if -k given. * Respawn a pane (restart the command). Kill existing if -k given.
*/ */
enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_respawn_pane_entry = { const struct cmd_entry cmd_respawn_pane_entry = {
.name = "respawn-pane", .name = "respawn-pane",
.alias = "respawnp", .alias = "respawnp",
.args = { "kt:", 0, -1 }, .args = { "c:e:kt:", 0, -1 },
.usage = "[-k] " CMD_TARGET_PANE_USAGE " [command]", .usage = "[-k] [-c start-directory] [-e environment] "
CMD_TARGET_PANE_USAGE " [command]",
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_respawn_pane_exec .exec = cmd_respawn_pane_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = cmdq->state.tflag.wl; struct spawn_context sc;
struct window *w = wl->window; struct session *s = item->target.s;
struct window_pane *wp = cmdq->state.tflag.wp; struct winlink *wl = item->target.wl;
struct session *s = cmdq->state.tflag.s; struct window_pane *wp = item->target.wp;
struct environ *env; char *cause = NULL;
const char *path; const char *add;
char *cause; struct args_value *value;
u_int idx;
struct environ_entry *envent;
if (!args_has(self->args, 'k') && wp->fd != -1) { memset(&sc, 0, sizeof sc);
if (window_pane_index(wp, &idx) != 0) sc.item = item;
fatalx("index not found"); sc.s = s;
cmdq_error(cmdq, "pane still active: %s:%d.%u", sc.wl = wl;
s->name, wl->idx, idx);
return (CMD_RETURN_ERROR); sc.wp0 = wp;
sc.lc = NULL;
sc.name = NULL;
sc.argc = args->argc;
sc.argv = args->argv;
sc.environ = environ_create();
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
add = args_next_value(&value);
} }
env = environ_create(); sc.idx = -1;
environ_copy(global_environ, env); sc.cwd = args_get(args, 'c');
environ_copy(s->environ, env);
server_fill_environ(s, env);
window_pane_reset_mode(wp); sc.flags = SPAWN_RESPAWN;
screen_reinit(&wp->base); if (args_has(args, 'k'))
input_init(wp); sc.flags |= SPAWN_KILL;
path = NULL; if (spawn_pane(&sc, &cause) == NULL) {
if (cmdq->client != NULL && cmdq->client->session == NULL) cmdq_error(item, "respawn pane failed: %s", cause);
envent = environ_find(cmdq->client->environ, "PATH");
else
envent = environ_find(s->environ, "PATH");
if (envent != NULL)
path = envent->value;
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env,
s->tio, &cause) != 0) {
cmdq_error(cmdq, "respawn pane failed: %s", cause);
free(cause); free(cause);
environ_free(env);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
wp->flags |= PANE_REDRAW;
server_status_window(w);
environ_free(env); wp->flags |= PANE_REDRAW;
server_status_window(wp->window);
environ_free(sc.environ);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -19,7 +19,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -27,81 +27,65 @@
* Respawn a window (restart the command). Kill existing if -k given. * Respawn a window (restart the command). Kill existing if -k given.
*/ */
enum cmd_retval cmd_respawn_window_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_respawn_window_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_respawn_window_entry = { const struct cmd_entry cmd_respawn_window_entry = {
.name = "respawn-window", .name = "respawn-window",
.alias = "respawnw", .alias = "respawnw",
.args = { "kt:", 0, -1 }, .args = { "c:e:kt:", 0, -1 },
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE " [command]", .usage = "[-k] [-c start-directory] [-e environment] "
CMD_TARGET_WINDOW_USAGE " [command]",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_respawn_window_exec .exec = cmd_respawn_window_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s = cmdq->state.tflag.s; struct spawn_context sc;
struct winlink *wl = cmdq->state.tflag.wl; struct session *s = item->target.s;
struct window *w = wl->window; struct winlink *wl = item->target.wl;
struct window_pane *wp; char *cause = NULL;
struct environ *env; const char *add;
const char *path; struct args_value *value;
char *cause;
struct environ_entry *envent;
if (!args_has(self->args, 'k')) { memset(&sc, 0, sizeof sc);
TAILQ_FOREACH(wp, &w->panes, entry) { sc.item = item;
if (wp->fd == -1) sc.s = s;
continue; sc.wl = wl;
cmdq_error(cmdq, "window still active: %s:%d", s->name,
wl->idx); sc.name = NULL;
return (CMD_RETURN_ERROR); sc.argc = args->argc;
} sc.argv = args->argv;
sc.environ = environ_create();
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
add = args_next_value(&value);
} }
env = environ_create(); sc.idx = -1;
environ_copy(global_environ, env); sc.cwd = args_get(args, 'c');
environ_copy(s->environ, env);
server_fill_environ(s, env);
wp = TAILQ_FIRST(&w->panes); sc.flags = SPAWN_RESPAWN;
TAILQ_REMOVE(&w->panes, wp, entry); if (args_has(args, 'k'))
layout_free(w); sc.flags |= SPAWN_KILL;
window_destroy_panes(w);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
window_pane_resize(wp, w->sx, w->sy);
path = NULL; if (spawn_window(&sc, &cause) == NULL) {
if (cmdq->client != NULL && cmdq->client->session == NULL) cmdq_error(item, "respawn window failed: %s", cause);
envent = environ_find(cmdq->client->environ, "PATH");
else
envent = environ_find(s->environ, "PATH");
if (envent != NULL)
path = envent->value;
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env,
s->tio, &cause) != 0) {
cmdq_error(cmdq, "respawn window failed: %s", cause);
free(cause); free(cause);
environ_free(env);
server_destroy_pane(wp, 0);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
layout_init(w, wp);
window_pane_reset_mode(wp);
screen_reinit(&wp->base);
input_init(wp);
window_set_active_pane(w, wp);
recalculate_sizes(); server_redraw_window(wl->window);
server_redraw_window(w);
environ_free(env); environ_free(sc.environ);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -24,7 +24,8 @@
* Rotate the panes in a window. * Rotate the panes in a window.
*/ */
enum cmd_retval cmd_rotate_window_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_rotate_window_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_rotate_window_entry = { const struct cmd_entry cmd_rotate_window_entry = {
.name = "rotate-window", .name = "rotate-window",
@@ -33,21 +34,24 @@ const struct cmd_entry cmd_rotate_window_entry = {
.args = { "Dt:U", 0, 0 }, .args = { "Dt:U", 0, 0 },
.usage = "[-DU] " CMD_TARGET_WINDOW_USAGE, .usage = "[-DU] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_rotate_window_exec .exec = cmd_rotate_window_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_rotate_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct winlink *wl = cmdq->state.tflag.wl; struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->target.wl;
struct window *w = wl->window; struct window *w = wl->window;
struct window_pane *wp, *wp2; struct window_pane *wp, *wp2;
struct layout_cell *lc; struct layout_cell *lc;
u_int sx, sy, xoff, yoff; u_int sx, sy, xoff, yoff;
server_unzoom_window(w);
if (args_has(self->args, 'D')) { if (args_has(self->args, 'D')) {
wp = TAILQ_LAST(&w->panes, window_panes); wp = TAILQ_LAST(&w->panes, window_panes);
TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_REMOVE(&w->panes, wp, entry);
@@ -73,7 +77,8 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_q *cmdq)
if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL) if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL)
wp = TAILQ_LAST(&w->panes, window_panes); wp = TAILQ_LAST(&w->panes, window_panes);
window_set_active_pane(w, wp); window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w); server_redraw_window(w);
} else { } else {
wp = TAILQ_FIRST(&w->panes); wp = TAILQ_FIRST(&w->panes);
@@ -100,7 +105,8 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_q *cmdq)
if ((wp = TAILQ_NEXT(w->active, entry)) == NULL) if ((wp = TAILQ_NEXT(w->active, entry)) == NULL)
wp = TAILQ_FIRST(&w->panes); wp = TAILQ_FIRST(&w->panes);
window_set_active_pane(w, wp); window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w); server_redraw_window(w);
} }

View File

@@ -29,11 +29,11 @@
* Runs a command without a window. * Runs a command without a window.
*/ */
enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmdq_item *);
void cmd_run_shell_callback(struct job *); static void cmd_run_shell_callback(struct job *);
void cmd_run_shell_free(void *); static void cmd_run_shell_free(void *);
void cmd_run_shell_print(struct job *, const char *); static void cmd_run_shell_print(struct job *, const char *);
const struct cmd_entry cmd_run_shell_entry = { const struct cmd_entry cmd_run_shell_entry = {
.name = "run-shell", .name = "run-shell",
@@ -42,133 +42,126 @@ const struct cmd_entry cmd_run_shell_entry = {
.args = { "bt:", 1, 1 }, .args = { "bt:", 1, 1 },
.usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command", .usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
.tflag = CMD_PANE_CANFAIL, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = 0, .flags = 0,
.exec = cmd_run_shell_exec .exec = cmd_run_shell_exec
}; };
struct cmd_run_shell_data { struct cmd_run_shell_data {
char *cmd; char *cmd;
struct cmd_q *cmdq; struct cmdq_item *item;
int bflag; int wp_id;
int wp_id;
}; };
void static void
cmd_run_shell_print(struct job *job, const char *msg) cmd_run_shell_print(struct job *job, const char *msg)
{ {
struct cmd_run_shell_data *cdata = job->data; struct cmd_run_shell_data *cdata = job_get_data(job);
struct window_pane *wp = NULL; struct window_pane *wp = NULL;
struct cmd_find_state fs;
struct window_mode_entry *wme;
if (cdata->wp_id != -1) if (cdata->wp_id != -1)
wp = window_pane_find_by_id(cdata->wp_id); wp = window_pane_find_by_id(cdata->wp_id);
if (wp == NULL) { if (wp == NULL) {
cmdq_print(cdata->cmdq, "%s", msg); if (cdata->item != NULL) {
return; cmdq_print(cdata->item, "%s", msg);
return;
}
if (cmd_find_from_nothing(&fs, 0) != 0)
return;
wp = fs.wp;
if (wp == NULL)
return;
} }
if (window_pane_set_mode(wp, &window_copy_mode) == 0) wme = TAILQ_FIRST(&wp->modes);
window_copy_init_for_output(wp); if (wme == NULL || wme->mode != &window_view_mode)
if (wp->mode == &window_copy_mode) window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
window_copy_add(wp, "%s", msg); window_copy_add(wp, "%s", msg);
} }
enum cmd_retval static enum cmd_retval
cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq) cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_run_shell_data *cdata; struct cmd_run_shell_data *cdata;
char *shellcmd; struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = cmdq->state.tflag.s; struct session *s = item->target.s;
struct winlink *wl = cmdq->state.tflag.wl; struct winlink *wl = item->target.wl;
struct window_pane *wp = cmdq->state.tflag.wp; struct window_pane *wp = item->target.wp;
struct format_tree *ft;
const char *cwd;
if (cmdq->client != NULL && cmdq->client->session == NULL) cdata = xcalloc(1, sizeof *cdata);
cwd = cmdq->client->cwd; cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
else if (s != NULL)
cwd = s->cwd; if (args_has(args, 't') && wp != NULL)
cdata->wp_id = wp->id;
else else
cwd = NULL; cdata->wp_id = -1;
ft = format_create(cmdq, 0);
format_defaults(ft, cmdq->state.c, s, wl, wp);
shellcmd = format_expand(ft, args->argv[0]);
format_free(ft);
cdata = xmalloc(sizeof *cdata); if (!args_has(args, 'b'))
cdata->cmd = shellcmd; cdata->item = item;
cdata->bflag = args_has(args, 'b');
cdata->wp_id = wp != NULL ? (int) wp->id : -1;
cdata->cmdq = cmdq; if (job_run(cdata->cmd, s, server_client_get_cwd(item->client, s), NULL,
cmdq->references++; cmd_run_shell_callback, cmd_run_shell_free, cdata, 0) == NULL) {
cmdq_error(item, "failed to run command: %s", cdata->cmd);
free(cdata);
return (CMD_RETURN_ERROR);
}
job_run(shellcmd, s, cwd, cmd_run_shell_callback, cmd_run_shell_free, if (args_has(args, 'b'))
cdata);
if (cdata->bflag)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
void static void
cmd_run_shell_callback(struct job *job) cmd_run_shell_callback(struct job *job)
{ {
struct cmd_run_shell_data *cdata = job->data; struct cmd_run_shell_data *cdata = job_get_data(job);
struct cmd_q *cmdq = cdata->cmdq; struct bufferevent *event = job_get_event(job);
char *cmd, *msg, *line; char *cmd = cdata->cmd, *msg = NULL, *line;
size_t size; size_t size;
int retcode; int retcode, status;
u_int lines;
if (cmdq->flags & CMD_Q_DEAD)
return;
cmd = cdata->cmd;
lines = 0;
do { do {
if ((line = evbuffer_readline(job->event->input)) != NULL) { if ((line = evbuffer_readline(event->input)) != NULL) {
cmd_run_shell_print(job, line); cmd_run_shell_print(job, line);
free(line); free(line);
lines++;
} }
} while (line != NULL); } while (line != NULL);
size = EVBUFFER_LENGTH(job->event->input); size = EVBUFFER_LENGTH(event->input);
if (size != 0) { if (size != 0) {
line = xmalloc(size + 1); line = xmalloc(size + 1);
memcpy(line, EVBUFFER_DATA(job->event->input), size); memcpy(line, EVBUFFER_DATA(event->input), size);
line[size] = '\0'; line[size] = '\0';
cmd_run_shell_print(job, line); cmd_run_shell_print(job, line);
lines++;
free(line); free(line);
} }
msg = NULL; status = job_get_status(job);
if (WIFEXITED(job->status)) { if (WIFEXITED(status)) {
if ((retcode = WEXITSTATUS(job->status)) != 0) if ((retcode = WEXITSTATUS(status)) != 0)
xasprintf(&msg, "'%s' returned %d", cmd, retcode); xasprintf(&msg, "'%s' returned %d", cmd, retcode);
} else if (WIFSIGNALED(job->status)) { } else if (WIFSIGNALED(status)) {
retcode = WTERMSIG(job->status); retcode = WTERMSIG(status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode); xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
} }
if (msg != NULL) if (msg != NULL)
cmd_run_shell_print(job, msg); cmd_run_shell_print(job, msg);
free(msg); free(msg);
if (cdata->item != NULL)
cmdq_continue(cdata->item);
} }
void static void
cmd_run_shell_free(void *data) cmd_run_shell_free(void *data)
{ {
struct cmd_run_shell_data *cdata = data; struct cmd_run_shell_data *cdata = data;
struct cmd_q *cmdq = cdata->cmdq;
if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq);
free(cdata->cmd); free(cdata->cmd);
free(cdata); free(cdata);

View File

@@ -31,7 +31,7 @@
* Saves a paste buffer to a file. * Saves a paste buffer to a file.
*/ */
enum cmd_retval cmd_save_buffer_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_save_buffer_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_save_buffer_entry = { const struct cmd_entry cmd_save_buffer_entry = {
.name = "save-buffer", .name = "save-buffer",
@@ -40,7 +40,7 @@ const struct cmd_entry cmd_save_buffer_entry = {
.args = { "ab:", 1, 1 }, .args = { "ab:", 1, 1 },
.usage = "[-a] " CMD_BUFFER_USAGE " path", .usage = "[-a] " CMD_BUFFER_USAGE " path",
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_save_buffer_exec .exec = cmd_save_buffer_exec
}; };
@@ -51,45 +51,48 @@ const struct cmd_entry cmd_show_buffer_entry = {
.args = { "b:", 0, 0 }, .args = { "b:", 0, 0 },
.usage = CMD_BUFFER_USAGE, .usage = CMD_BUFFER_USAGE,
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_save_buffer_exec .exec = cmd_save_buffer_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq) cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmdq->client; struct client *c = cmd_find_client(item, NULL, 1);
struct session *s; struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
struct paste_buffer *pb; struct paste_buffer *pb;
const char *path, *bufname, *bufdata, *start, *end, *cwd; const char *bufname, *bufdata, *start, *end, *flags;
const char *flags; char *msg, *path, *file;
char *msg, *file, resolved[PATH_MAX];
size_t size, used, msglen, bufsize; size_t size, used, msglen, bufsize;
FILE *f; FILE *f;
if (!args_has(args, 'b')) { if (!args_has(args, 'b')) {
if ((pb = paste_get_top(NULL)) == NULL) { if ((pb = paste_get_top(NULL)) == NULL) {
cmdq_error(cmdq, "no buffers"); cmdq_error(item, "no buffers");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else { } else {
bufname = args_get(args, 'b'); bufname = args_get(args, 'b');
pb = paste_get_name(bufname); pb = paste_get_name(bufname);
if (pb == NULL) { if (pb == NULL) {
cmdq_error(cmdq, "no buffer %s", bufname); cmdq_error(item, "no buffer %s", bufname);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
bufdata = paste_buffer_data(pb, &bufsize); bufdata = paste_buffer_data(pb, &bufsize);
if (self->entry == &cmd_show_buffer_entry) if (self->entry == &cmd_show_buffer_entry)
path = "-"; path = xstrdup("-");
else else
path = args->argv[0]; path = format_single(item, args->argv[0], c, s, wl, wp);
if (strcmp(path, "-") == 0) { if (strcmp(path, "-") == 0) {
free(path);
c = item->client;
if (c == NULL) { if (c == NULL) {
cmdq_error(cmdq, "can't write to stdout"); cmdq_error(item, "can't write to stdout");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (c->session == NULL || (c->flags & CLIENT_CONTROL)) if (c->session == NULL || (c->flags & CLIENT_CONTROL))
@@ -97,39 +100,29 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
goto do_print; goto do_print;
} }
if (c != NULL && c->session == NULL && c->cwd != NULL)
cwd = c->cwd;
else if ((s = c->session) != NULL && s->cwd != NULL)
cwd = s->cwd;
else
cwd = ".";
flags = "wb"; flags = "wb";
if (args_has(self->args, 'a')) if (args_has(self->args, 'a'))
flags = "ab"; flags = "ab";
if (*path == '/') file = server_client_get_path(item->client, path);
file = xstrdup(path); free(path);
else
xasprintf(&file, "%s/%s", cwd, path); f = fopen(file, flags);
if (realpath(file, resolved) == NULL &&
strlcpy(resolved, file, sizeof resolved) >= sizeof resolved) {
cmdq_error(cmdq, "%s: %s", file, strerror(ENAMETOOLONG));
return (CMD_RETURN_ERROR);
}
f = fopen(resolved, flags);
free(file);
if (f == NULL) { if (f == NULL) {
cmdq_error(cmdq, "%s: %s", resolved, strerror(errno)); cmdq_error(item, "%s: %s", file, strerror(errno));
free(file);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (fwrite(bufdata, 1, bufsize, f) != bufsize) { if (fwrite(bufdata, 1, bufsize, f) != bufsize) {
cmdq_error(cmdq, "%s: write error", resolved); cmdq_error(item, "%s: write error", file);
fclose(f); fclose(f);
free(file);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
fclose(f); fclose(f);
free(file);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -140,7 +133,7 @@ do_stdout:
do_print: do_print:
if (bufsize > (INT_MAX / 4) - 1) { if (bufsize > (INT_MAX / 4) - 1) {
cmdq_error(cmdq, "buffer too big"); cmdq_error(item, "buffer too big");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
msg = NULL; msg = NULL;
@@ -158,7 +151,7 @@ do_print:
msg = xrealloc(msg, msglen); msg = xrealloc(msg, msglen);
strvisx(msg, start, size, VIS_OCTAL|VIS_TAB); strvisx(msg, start, size, VIS_OCTAL|VIS_TAB);
cmdq_print(cmdq, "%s", msg); cmdq_print(item, "%s", msg);
used += size + (end != NULL); used += size + (end != NULL);
} }

View File

@@ -26,18 +26,19 @@
* Switch window to selected layout. * Switch window to selected layout.
*/ */
enum cmd_retval cmd_select_layout_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_select_layout_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_select_layout_entry = { const struct cmd_entry cmd_select_layout_entry = {
.name = "select-layout", .name = "select-layout",
.alias = "selectl", .alias = "selectl",
.args = { "nopt:", 0, 1 }, .args = { "Enopt:", 0, 1 },
.usage = "[-nop] " CMD_TARGET_WINDOW_USAGE " [layout-name]", .usage = "[-Enop] " CMD_TARGET_PANE_USAGE " [layout-name]",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec .exec = cmd_select_layout_exec
}; };
@@ -48,9 +49,9 @@ const struct cmd_entry cmd_next_layout_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE, .usage = CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec .exec = cmd_select_layout_exec
}; };
@@ -61,23 +62,23 @@ const struct cmd_entry cmd_previous_layout_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE, .usage = CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec .exec = cmd_select_layout_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq) cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = cmdq->state.tflag.wl; struct winlink *wl = item->target.wl;
struct window *w; struct window *w = wl->window;
const char *layoutname; struct window_pane *wp = item->target.wp;
char *oldlayout; const char *layoutname;
int next, previous, layout; char *oldlayout;
int next, previous, layout;
w = wl->window;
server_unzoom_window(w); server_unzoom_window(w);
next = self->entry == &cmd_next_layout_entry; next = self->entry == &cmd_next_layout_entry;
@@ -98,6 +99,11 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq)
goto changed; goto changed;
} }
if (args_has(args, 'E')) {
layout_spread_out(wp);
goto changed;
}
if (!args_has(args, 'o')) { if (!args_has(args, 'o')) {
if (args->argc == 0) if (args->argc == 0)
layout = w->lastlayout; layout = w->lastlayout;
@@ -118,7 +124,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq)
if (layoutname != NULL) { if (layoutname != NULL) {
if (layout_parse(w, layoutname) == -1) { if (layout_parse(w, layoutname) == -1) {
cmdq_error(cmdq, "can't set layout: %s", layoutname); cmdq_error(item, "can't set layout: %s", layoutname);
goto error; goto error;
} }
goto changed; goto changed;
@@ -129,7 +135,9 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq)
changed: changed:
free(oldlayout); free(oldlayout);
recalculate_sizes();
server_redraw_window(w); server_redraw_window(w);
notify_window("window-layout-changed", w);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
error: error:

View File

@@ -18,22 +18,25 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Select pane. * Select pane.
*/ */
enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_select_pane_entry = { const struct cmd_entry cmd_select_pane_entry = {
.name = "select-pane", .name = "select-pane",
.alias = "selectp", .alias = "selectp",
.args = { "DdegLlMmP:Rt:U", 0, 0 }, .args = { "DdegLlMmP:RT:t:U", 0, 0 }, /* -P and -g deprecated */
.usage = "[-DdegLlMmRU] [-P style] " CMD_TARGET_PANE_USAGE, .usage = "[-DdeLlMmRU] [-T title] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_select_pane_exec .exec = cmd_select_pane_exec
@@ -46,42 +49,75 @@ const struct cmd_entry cmd_last_pane_entry = {
.args = { "det:", 0, 0 }, .args = { "det:", 0, 0 },
.usage = "[-de] " CMD_TARGET_WINDOW_USAGE, .usage = "[-de] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_select_pane_exec .exec = cmd_select_pane_exec
}; };
enum cmd_retval static void
cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_select_pane_redraw(struct window *w)
{
struct client *c;
/*
* Redraw entire window if it is bigger than the client (the
* offset may change), otherwise just draw borders.
*/
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == NULL || (c->flags & CLIENT_CONTROL))
continue;
if (c->session->curw->window == w && tty_window_bigger(&c->tty))
server_redraw_client(c);
else {
if (c->session->curw->window == w)
c->flags |= CLIENT_REDRAWBORDERS;
if (session_has(c->session, w))
c->flags |= CLIENT_REDRAWSTATUS;
}
}
}
static enum cmd_retval
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = cmdq->state.tflag.wl; struct cmd_find_state *current = &item->shared->current;
struct client *c = cmd_find_client(item, NULL, 1);
struct winlink *wl = item->target.wl;
struct window *w = wl->window; struct window *w = wl->window;
struct session *s = cmdq->state.tflag.s; struct session *s = item->target.s;
struct window_pane *wp = cmdq->state.tflag.wp, *lastwp, *markedwp; struct window_pane *wp = item->target.wp, *lastwp, *markedwp;
char *pane_title;
const char *style; const char *style;
struct style *sy;
struct options_entry *o;
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) { if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
lastwp = w->last;
if (wl->window->last == NULL) { if (lastwp == NULL && window_count_panes(w) == 2) {
cmdq_error(cmdq, "no last pane"); lastwp = TAILQ_PREV(w->active, window_panes, entry);
if (lastwp == NULL)
lastwp = TAILQ_NEXT(w->active, entry);
}
if (lastwp == NULL) {
cmdq_error(item, "no last pane");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(self->args, 'e')) if (args_has(self->args, 'e'))
w->last->flags &= ~PANE_INPUTOFF; lastwp->flags &= ~PANE_INPUTOFF;
else if (args_has(self->args, 'd')) else if (args_has(self->args, 'd'))
w->last->flags |= PANE_INPUTOFF; lastwp->flags |= PANE_INPUTOFF;
else { else {
server_unzoom_window(w); server_unzoom_window(w);
window_redraw_active_switch(w, w->last); window_redraw_active_switch(w, lastwp);
if (window_set_active_pane(w, w->last)) { if (window_set_active_pane(w, lastwp, 1)) {
server_status_window(w); cmd_find_from_winlink(current, wl, 0);
server_redraw_window_borders(w); cmd_select_pane_redraw(w);
} }
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -108,17 +144,21 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
} }
if (args_has(self->args, 'P') || args_has(self->args, 'g')) { if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
if (args_has(args, 'P')) { if ((style = args_get(args, 'P')) != NULL) {
style = args_get(args, 'P'); o = options_set_style(wp->options, "window-style", 0,
if (style_parse(&grid_default_cell, &wp->colgc, style);
style) == -1) { if (o == NULL) {
cmdq_error(cmdq, "bad style: %s", style); cmdq_error(item, "bad style: %s", style);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
wp->flags |= PANE_REDRAW; options_set_style(wp->options, "window-active-style", 0,
style);
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
}
if (args_has(self->args, 'g')) {
sy = options_get_style(wp->options, "window-style");
cmdq_print(item, "%s", style_tostring(sy));
} }
if (args_has(self->args, 'g'))
cmdq_print(cmdq, "%s", style_tostring(&wp->colgc));
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -147,17 +187,23 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(self->args, 'T')) {
pane_title = format_single(item, args_get(self->args, 'T'),
c, s, wl, wp);
screen_set_title(&wp->base, pane_title);
server_status_window(wp->window);
free(pane_title);
return (CMD_RETURN_NORMAL);
}
if (wp == w->active) if (wp == w->active)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
server_unzoom_window(wp->window); server_unzoom_window(wp->window);
if (!window_pane_visible(wp)) {
cmdq_error(cmdq, "pane not visible");
return (CMD_RETURN_ERROR);
}
window_redraw_active_switch(w, wp); window_redraw_active_switch(w, wp);
if (window_set_active_pane(w, wp)) { if (window_set_active_pane(w, wp, 1)) {
server_status_window(w); cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window_borders(w); cmdq_insert_hook(s, item, current, "after-select-pane");
cmd_select_pane_redraw(w);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -26,7 +26,8 @@
* Select window by index. * Select window by index.
*/ */
enum cmd_retval cmd_select_window_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_select_window_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_select_window_entry = { const struct cmd_entry cmd_select_window_entry = {
.name = "select-window", .name = "select-window",
@@ -35,7 +36,7 @@ const struct cmd_entry cmd_select_window_entry = {
.args = { "lnpTt:", 0, 0 }, .args = { "lnpTt:", 0, 0 },
.usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE, .usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_select_window_exec .exec = cmd_select_window_exec
@@ -48,7 +49,7 @@ const struct cmd_entry cmd_next_window_entry = {
.args = { "at:", 0, 0 }, .args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE, .usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0, .flags = 0,
.exec = cmd_select_window_exec .exec = cmd_select_window_exec
@@ -61,7 +62,7 @@ const struct cmd_entry cmd_previous_window_entry = {
.args = { "at:", 0, 0 }, .args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE, .usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0, .flags = 0,
.exec = cmd_select_window_exec .exec = cmd_select_window_exec
@@ -74,18 +75,19 @@ const struct cmd_entry cmd_last_window_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE, .usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0, .flags = 0,
.exec = cmd_select_window_exec .exec = cmd_select_window_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_select_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct winlink *wl = cmdq->state.tflag.wl; struct cmd_find_state *current = &item->shared->current;
struct session *s = cmdq->state.tflag.s; struct winlink *wl = item->target.wl;
int next, previous, last, activity; struct session *s = item->target.s;
int next, previous, last, activity;
next = self->entry == &cmd_next_window_entry; next = self->entry == &cmd_next_window_entry;
if (args_has(self->args, 'n')) if (args_has(self->args, 'n'))
@@ -101,22 +103,23 @@ cmd_select_window_exec(struct cmd *self, struct cmd_q *cmdq)
activity = args_has(self->args, 'a'); activity = args_has(self->args, 'a');
if (next) { if (next) {
if (session_next(s, activity) != 0) { if (session_next(s, activity) != 0) {
cmdq_error(cmdq, "no next window"); cmdq_error(item, "no next window");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else if (previous) { } else if (previous) {
if (session_previous(s, activity) != 0) { if (session_previous(s, activity) != 0) {
cmdq_error(cmdq, "no previous window"); cmdq_error(item, "no previous window");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else { } else {
if (session_last(s) != 0) { if (session_last(s) != 0) {
cmdq_error(cmdq, "no last window"); cmdq_error(item, "no last window");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
cmd_find_from_session(current, s, 0);
server_redraw_session(s); server_redraw_session(s);
cmdq_insert_hook(s, item, current, "after-select-window");
} else { } else {
/* /*
* If -T and select-window is invoked on same window as * If -T and select-window is invoked on same window as
@@ -124,12 +127,17 @@ cmd_select_window_exec(struct cmd *self, struct cmd_q *cmdq)
*/ */
if (args_has(self->args, 'T') && wl == s->curw) { if (args_has(self->args, 'T') && wl == s->curw) {
if (session_last(s) != 0) { if (session_last(s) != 0) {
cmdq_error(cmdq, "no last window"); cmdq_error(item, "no last window");
return (-1); return (-1);
} }
if (current->s == s)
cmd_find_from_session(current, s, 0);
server_redraw_session(s); server_redraw_session(s);
} else if (session_select(s, wl->idx) == 0) } else if (session_select(s, wl->idx) == 0) {
cmd_find_from_session(current, s, 0);
server_redraw_session(s); server_redraw_session(s);
}
cmdq_insert_hook(s, item, current, "after-select-window");
} }
recalculate_sizes(); recalculate_sizes();

View File

@@ -27,18 +27,18 @@
* Send keys to client. * Send keys to client.
*/ */
enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_send_keys_entry = { const struct cmd_entry cmd_send_keys_entry = {
.name = "send-keys", .name = "send-keys",
.alias = "send", .alias = "send",
.args = { "lRMt:", 0, -1 }, .args = { "HlXRMN:t:", 0, -1 },
.usage = "[-lRM] " CMD_TARGET_PANE_USAGE " key ...", .usage = "[-HlXRM] [-N repeat-count] " CMD_TARGET_PANE_USAGE " key ...",
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_send_keys_exec .exec = cmd_send_keys_exec
}; };
@@ -49,30 +49,126 @@ const struct cmd_entry cmd_send_prefix_entry = {
.args = { "2t:", 0, 0 }, .args = { "2t:", 0, 0 },
.usage = "[-2] " CMD_TARGET_PANE_USAGE, .usage = "[-2] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_send_keys_exec .exec = cmd_send_keys_exec
}; };
enum cmd_retval static struct cmdq_item *
cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq) cmd_send_keys_inject_key(struct client *c, struct cmd_find_state *fs,
struct cmdq_item *item, key_code key)
{ {
struct args *args = self->args; struct window_mode_entry *wme;
struct window_pane *wp = cmdq->state.tflag.wp; struct key_table *table;
struct session *s = cmdq->state.tflag.s; struct key_binding *bd;
struct mouse_event *m = &cmdq->item->mouse;
const u_char *keystr; wme = TAILQ_FIRST(&fs->wp->modes);
int i, literal; if (wme == NULL || wme->mode->key_table == NULL) {
if (options_get_number(fs->wp->window->options, "xterm-keys"))
key |= KEYC_XTERM;
window_pane_key(fs->wp, item->client, fs->s, fs->wl, key, NULL);
return (item);
}
table = key_bindings_get_table(wme->mode->key_table(wme), 1);
bd = key_bindings_get(table, key & ~KEYC_XTERM);
if (bd != NULL) {
table->references++;
item = key_bindings_dispatch(bd, item, c, NULL, &item->target);
key_bindings_unref_table(table);
}
return (item);
}
static struct cmdq_item *
cmd_send_keys_inject_string(struct client *c, struct cmd_find_state *fs,
struct cmdq_item *item, struct args *args, int i)
{
const char *s = args->argv[i];
struct utf8_data *ud, *uc;
wchar_t wc;
key_code key; key_code key;
char *endptr;
long n;
int literal;
if (args_has(args, 'H')) {
n = strtol(s, &endptr, 16);
if (*s =='\0' || n < 0 || n > 0xff || *endptr != '\0')
return (item);
return (cmd_send_keys_inject_key(c, fs, item, KEYC_LITERAL|n));
}
literal = args_has(args, 'l');
if (!literal) {
key = key_string_lookup_string(s);
if (key != KEYC_NONE && key != KEYC_UNKNOWN)
return (cmd_send_keys_inject_key(c, fs, item, key));
literal = 1;
}
if (literal) {
ud = utf8_fromcstr(s);
for (uc = ud; uc->size != 0; uc++) {
if (utf8_combine(uc, &wc) != UTF8_DONE)
continue;
item = cmd_send_keys_inject_key(c, fs, item, wc);
}
free(ud);
}
return (item);
}
static enum cmd_retval
cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = cmd_find_client(item, NULL, 1);
struct cmd_find_state *fs = &item->target;
struct window_pane *wp = item->target.wp;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct mouse_event *m = &item->shared->mouse;
struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
int i;
key_code key;
u_int np = 1;
char *cause = NULL;
if (args_has(args, 'N')) {
np = args_strtonum(args, 'N', 1, UINT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "repeat count %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (wme != NULL && (args_has(args, 'X') || args->argc == 0)) {
if (wme == NULL || wme->mode->command == NULL) {
cmdq_error(item, "not in a mode");
return (CMD_RETURN_ERROR);
}
wme->prefix = np;
}
}
if (args_has(args, 'X')) {
if (wme == NULL || wme->mode->command == NULL) {
cmdq_error(item, "not in a mode");
return (CMD_RETURN_ERROR);
}
if (!m->valid)
m = NULL;
wme->mode->command(wme, c, s, wl, args, m);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
wp = cmd_mouse_pane(m, &s, NULL); wp = cmd_mouse_pane(m, &s, NULL);
if (wp == NULL) { if (wp == NULL) {
cmdq_error(cmdq, "no mouse target"); cmdq_error(item, "no mouse target");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
window_pane_key(wp, NULL, s, m->key, m); window_pane_key(wp, item->client, s, wl, m->key, m);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -81,26 +177,18 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq)
key = options_get_number(s->options, "prefix2"); key = options_get_number(s->options, "prefix2");
else else
key = options_get_number(s->options, "prefix"); key = options_get_number(s->options, "prefix");
window_pane_key(wp, NULL, s, key, NULL); cmd_send_keys_inject_key(c, fs, item, key);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'R')) if (args_has(args, 'R')) {
window_pane_reset_palette(wp);
input_reset(wp, 1); input_reset(wp, 1);
}
for (i = 0; i < args->argc; i++) { for (; np != 0; np--) {
literal = args_has(args, 'l'); for (i = 0; i < args->argc; i++)
if (!literal) { item = cmd_send_keys_inject_string(c, fs, item, args, i);
key = key_string_lookup_string(args->argv[i]);
if (key != KEYC_NONE && key != KEYC_UNKNOWN)
window_pane_key(wp, NULL, s, key, NULL);
else
literal = 1;
}
if (literal) {
for (keystr = args->argv[i]; *keystr != '\0'; keystr++)
window_pane_key(wp, NULL, s, *keystr, NULL);
}
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -27,7 +27,7 @@
* Add, set, append to or delete a paste buffer. * Add, set, append to or delete a paste buffer.
*/ */
enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_set_buffer_entry = { const struct cmd_entry cmd_set_buffer_entry = {
.name = "set-buffer", .name = "set-buffer",
@@ -36,7 +36,7 @@ const struct cmd_entry cmd_set_buffer_entry = {
.args = { "ab:n:", 0, 1 }, .args = { "ab:n:", 0, 1 },
.usage = "[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data", .usage = "[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_set_buffer_exec .exec = cmd_set_buffer_exec
}; };
@@ -47,12 +47,12 @@ const struct cmd_entry cmd_delete_buffer_entry = {
.args = { "b:", 0, 0 }, .args = { "b:", 0, 0 },
.usage = CMD_BUFFER_USAGE, .usage = CMD_BUFFER_USAGE,
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_set_buffer_exec .exec = cmd_set_buffer_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq) cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct paste_buffer *pb; struct paste_buffer *pb;
@@ -70,7 +70,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
if (pb == NULL) if (pb == NULL)
pb = paste_get_top(&bufname); pb = paste_get_top(&bufname);
if (pb == NULL) { if (pb == NULL) {
cmdq_error(cmdq, "no buffer"); cmdq_error(item, "no buffer");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
paste_free(pb); paste_free(pb);
@@ -81,11 +81,11 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
if (pb == NULL) if (pb == NULL)
pb = paste_get_top(&bufname); pb = paste_get_top(&bufname);
if (pb == NULL) { if (pb == NULL) {
cmdq_error(cmdq, "no buffer"); cmdq_error(item, "no buffer");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) { if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) {
cmdq_error(cmdq, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -93,7 +93,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
} }
if (args->argc != 1) { if (args->argc != 1) {
cmdq_error(cmdq, "no data specified"); cmdq_error(item, "no data specified");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if ((newsize = strlen(args->argv[0])) == 0) if ((newsize = strlen(args->argv[0])) == 0)
@@ -113,7 +113,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
bufsize += newsize; bufsize += newsize;
if (paste_set(bufdata, bufsize, bufname, &cause) != 0) { if (paste_set(bufdata, bufsize, bufname, &cause) != 0) {
cmdq_error(cmdq, "%s", cause); cmdq_error(item, "%s", cause);
free(bufdata); free(bufdata);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);

View File

@@ -27,7 +27,8 @@
* Set an environment variable. * Set an environment variable.
*/ */
enum cmd_retval cmd_set_environment_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_set_environment_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_set_environment_entry = { const struct cmd_entry cmd_set_environment_entry = {
.name = "set-environment", .name = "set-environment",
@@ -36,14 +37,14 @@ const struct cmd_entry cmd_set_environment_entry = {
.args = { "grt:u", 1, 2 }, .args = { "grt:u", 1, 2 },
.usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]", .usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
.tflag = CMD_SESSION_CANFAIL, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_set_environment_exec .exec = cmd_set_environment_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq) cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct environ *env; struct environ *env;
@@ -51,11 +52,11 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq)
name = args->argv[0]; name = args->argv[0];
if (*name == '\0') { if (*name == '\0') {
cmdq_error(cmdq, "empty variable name"); cmdq_error(item, "empty variable name");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (strchr(name, '=') != NULL) { if (strchr(name, '=') != NULL) {
cmdq_error(cmdq, "variable name contains ="); cmdq_error(item, "variable name contains =");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -67,32 +68,32 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(self->args, 'g')) if (args_has(self->args, 'g'))
env = global_environ; env = global_environ;
else { else {
if (cmdq->state.tflag.s == NULL) { if (item->target.s == NULL) {
target = args_get(args, 't'); target = args_get(args, 't');
if (target != NULL) if (target != NULL)
cmdq_error(cmdq, "no such session: %s", target); cmdq_error(item, "no such session: %s", target);
else else
cmdq_error(cmdq, "no current session"); cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
env = cmdq->state.tflag.s->environ; env = item->target.s->environ;
} }
if (args_has(self->args, 'u')) { if (args_has(self->args, 'u')) {
if (value != NULL) { if (value != NULL) {
cmdq_error(cmdq, "can't specify a value with -u"); cmdq_error(item, "can't specify a value with -u");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
environ_unset(env, name); environ_unset(env, name);
} else if (args_has(self->args, 'r')) { } else if (args_has(self->args, 'r')) {
if (value != NULL) { if (value != NULL) {
cmdq_error(cmdq, "can't specify a value with -r"); cmdq_error(item, "can't specify a value with -r");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
environ_clear(env, name); environ_clear(env, name);
} else { } else {
if (value == NULL) { if (value == NULL) {
cmdq_error(cmdq, "no value specified"); cmdq_error(item, "no value specified");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
environ_set(env, name, "%s", value); environ_set(env, name, "%s", value);

View File

@@ -1,129 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Set or show global or session hooks.
*/
enum cmd_retval cmd_set_hook_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_set_hook_entry = {
.name = "set-hook",
.alias = NULL,
.args = { "gt:u", 1, 2 },
.usage = "[-gu] " CMD_TARGET_SESSION_USAGE " hook-name [command]",
.tflag = CMD_SESSION_CANFAIL,
.flags = 0,
.exec = cmd_set_hook_exec
};
const struct cmd_entry cmd_show_hooks_entry = {
.name = "show-hooks",
.alias = NULL,
.args = { "gt:", 0, 1 },
.usage = "[-g] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_set_hook_exec
};
enum cmd_retval
cmd_set_hook_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct cmd_list *cmdlist;
struct hooks *hooks;
struct hook *hook;
char *cause, *tmp;
const char *name, *cmd, *target;
if (args_has(args, 'g'))
hooks = global_hooks;
else {
if (cmdq->state.tflag.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(cmdq, "no such session: %s", target);
else
cmdq_error(cmdq, "no current session");
return (CMD_RETURN_ERROR);
}
hooks = cmdq->state.tflag.s->hooks;
}
if (self->entry == &cmd_show_hooks_entry) {
hook = hooks_first(hooks);
while (hook != NULL) {
tmp = cmd_list_print(hook->cmdlist);
cmdq_print(cmdq, "%s -> %s", hook->name, tmp);
free(tmp);
hook = hooks_next(hook);
}
return (CMD_RETURN_NORMAL);
}
name = args->argv[0];
if (*name == '\0') {
cmdq_error(cmdq, "invalid hook name");
return (CMD_RETURN_ERROR);
}
if (args->argc < 2)
cmd = NULL;
else
cmd = args->argv[1];
if (args_has(args, 'u')) {
if (cmd != NULL) {
cmdq_error(cmdq, "command passed to unset hook: %s",
name);
return (CMD_RETURN_ERROR);
}
hooks_remove(hooks, name);
return (CMD_RETURN_NORMAL);
}
if (cmd == NULL) {
cmdq_error(cmdq, "no command to set hook: %s", name);
return (CMD_RETURN_ERROR);
}
if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) {
cmdq_error(cmdq, "%s", cause);
free(cause);
}
return (CMD_RETURN_ERROR);
}
hooks_add(hooks, name, cmdlist);
cmd_list_free(cmdlist);
return (CMD_RETURN_NORMAL);
}

View File

@@ -18,6 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -27,53 +28,27 @@
* Set an option. * Set an option.
*/ */
enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmdq_item *);
enum cmd_retval cmd_set_option_user(struct cmd *, struct cmd_q *, static int cmd_set_option_set(struct cmd *, struct cmdq_item *,
const char *, const char *); struct options *, struct options_entry *, const char *);
static int cmd_set_option_flag(struct cmdq_item *,
int cmd_set_option_unset(struct cmd *, struct cmd_q *, const struct options_table_entry *, struct options *,
const struct options_table_entry *, struct options *, const char *);
const char *); static int cmd_set_option_choice(struct cmdq_item *,
int cmd_set_option_set(struct cmd *, struct cmd_q *, const struct options_table_entry *, struct options *,
const struct options_table_entry *, struct options *, const char *);
const char *);
struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_key(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_attributes(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_style(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
const struct cmd_entry cmd_set_option_entry = { const struct cmd_entry cmd_set_option_entry = {
.name = "set-option", .name = "set-option",
.alias = "set", .alias = "set",
.args = { "agoqst:uw", 1, 2 }, .args = { "aFgopqst:uw", 1, 2 },
.usage = "[-agosquw] [-t target-window] option [value]", .usage = "[-aFgopqsuw] " CMD_TARGET_PANE_USAGE " option [value]",
.tflag = CMD_WINDOW_CANFAIL, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec .exec = cmd_set_option_exec
}; };
@@ -81,385 +56,309 @@ const struct cmd_entry cmd_set_window_option_entry = {
.name = "set-window-option", .name = "set-window-option",
.alias = "setw", .alias = "setw",
.args = { "agoqt:u", 1, 2 }, .args = { "aFgoqt:u", 1, 2 },
.usage = "[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]", .usage = "[-aFgoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
.tflag = CMD_WINDOW_CANFAIL, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec .exec = cmd_set_option_exec
}; };
enum cmd_retval const struct cmd_entry cmd_set_hook_entry = {
cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq) .name = "set-hook",
{ .alias = NULL,
struct args *args = self->args;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
struct window *w;
struct client *c;
const struct options_table_entry *oe;
struct options *oo;
const char *optstr, *valstr, *target;
/* Get the option name and value. */ .args = { "agRt:u", 1, 2 },
optstr = args->argv[0]; .usage = "[-agRu] " CMD_TARGET_SESSION_USAGE " hook [command]",
if (*optstr == '\0') {
cmdq_error(cmdq, "invalid option"); .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
return (CMD_RETURN_ERROR);
.flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec
};
static enum cmd_retval
cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
int append = args_has(args, 'a');
struct cmd_find_state *fs = &item->target;
struct client *c, *loop;
struct session *s = fs->s;
struct winlink *wl = fs->wl;
struct window *w;
struct window_pane *wp;
struct options *oo;
struct options_entry *parent, *o;
char *name, *argument, *value = NULL, *cause;
int window, idx, already, error, ambiguous;
int scope;
struct style *sy;
window = (self->entry == &cmd_set_window_option_entry);
/* Expand argument. */
c = cmd_find_client(item, NULL, 1);
argument = format_single(item, args->argv[0], c, s, wl, NULL);
/* If set-hook -R, fire the hook straight away. */
if (self->entry == &cmd_set_hook_entry && args_has(args, 'R')) {
notify_hook(item, argument);
free(argument);
return (CMD_RETURN_NORMAL);
}
/* Parse option name and index. */
name = options_match(argument, &idx, &ambiguous);
if (name == NULL) {
if (args_has(args, 'q'))
goto out;
if (ambiguous)
cmdq_error(item, "ambiguous option: %s", argument);
else
cmdq_error(item, "invalid option: %s", argument);
goto fail;
} }
if (args->argc < 2) if (args->argc < 2)
valstr = NULL; value = NULL;
else if (args_has(args, 'F'))
value = format_single(item, args->argv[1], c, s, wl, NULL);
else else
valstr = args->argv[1]; value = xstrdup(args->argv[1]);
/* Is this a user option? */ /* Get the scope and table for the option .*/
if (*optstr == '@') scope = options_scope_from_name(args, window, name, fs, &oo, &cause);
return (cmd_set_option_user(self, cmdq, optstr, valstr)); if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
goto out;
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
}
o = options_get_only(oo, name);
parent = options_get(oo, name);
/* Find the option entry, try each table. */ /* Check that array options and indexes match up. */
oe = NULL; if (idx != -1 && (*name == '@' || !options_isarray(parent))) {
if (options_table_find(optstr, &oe) != 0) { cmdq_error(item, "not an array: %s", argument);
if (!args_has(args, 'q')) { goto fail;
cmdq_error(cmdq, "ambiguous option: %s", optstr); }
return (CMD_RETURN_ERROR);
/* With -o, check this option is not already set. */
if (!args_has(args, 'u') && args_has(args, 'o')) {
if (idx == -1)
already = (o != NULL);
else {
if (o == NULL)
already = 0;
else
already = (options_array_get(o, idx) != NULL);
} }
return (CMD_RETURN_NORMAL); if (already) {
} if (args_has(args, 'q'))
if (oe == NULL) { goto out;
if (!args_has(args, 'q')) { cmdq_error(item, "already set: %s", argument);
cmdq_error(cmdq, "unknown option: %s", optstr); goto fail;
return (CMD_RETURN_ERROR);
} }
return (CMD_RETURN_NORMAL);
} }
/* Work out the tree from the scope of the option. */ /* Change the option. */
if (oe->scope == OPTIONS_TABLE_SERVER)
oo = global_options;
else if (oe->scope == OPTIONS_TABLE_WINDOW) {
if (args_has(self->args, 'g'))
oo = global_w_options;
else if (wl == NULL) {
target = args_get(args, 't');
if (target != NULL) {
cmdq_error(cmdq, "no such window: %s",
target);
} else
cmdq_error(cmdq, "no current window");
return (CMD_RETURN_ERROR);
} else
oo = wl->window->options;
} else if (oe->scope == OPTIONS_TABLE_SESSION) {
if (args_has(self->args, 'g'))
oo = global_s_options;
else if (s == NULL) {
target = args_get(args, 't');
if (target != NULL) {
cmdq_error(cmdq, "no such session: %s",
target);
} else
cmdq_error(cmdq, "no current session");
return (CMD_RETURN_ERROR);
} else
oo = s->options;
} else {
cmdq_error(cmdq, "unknown table");
return (CMD_RETURN_ERROR);
}
/* Unset or set the option. */
if (args_has(args, 'u')) { if (args_has(args, 'u')) {
if (cmd_set_option_unset(self, cmdq, oe, oo, valstr) != 0) if (o == NULL)
return (CMD_RETURN_ERROR); goto out;
} else { if (idx == -1) {
if (args_has(args, 'o') && options_find1(oo, optstr) != NULL) { if (*name == '@')
if (!args_has(args, 'q')) { options_remove(o);
cmdq_error(cmdq, "already set: %s", optstr); else if (oo == global_options ||
return (CMD_RETURN_ERROR); oo == global_s_options ||
} oo == global_w_options)
return (CMD_RETURN_NORMAL); options_default(oo, options_table_entry(o));
else
options_remove(o);
} else if (options_array_set(o, idx, NULL, 0, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
}
} else if (*name == '@') {
if (value == NULL) {
cmdq_error(item, "empty value");
goto fail;
}
options_set_string(oo, name, append, "%s", value);
} else if (idx == -1 && !options_isarray(parent)) {
error = cmd_set_option_set(self, item, oo, parent, value);
if (error != 0)
goto fail;
} else {
if (value == NULL) {
cmdq_error(item, "empty value");
goto fail;
}
if (o == NULL)
o = options_empty(oo, options_table_entry(parent));
if (idx == -1) {
if (!append)
options_array_clear(o);
if (options_array_assign(o, value, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
}
} else if (options_array_set(o, idx, value, append,
&cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
} }
if (cmd_set_option_set(self, cmdq, oe, oo, valstr) != 0)
return (CMD_RETURN_ERROR);
} }
/* Start or stop timers if necessary. */ /* Update timers and so on for various options. */
if (strcmp(oe->name, "automatic-rename") == 0) { if (strcmp(name, "automatic-rename") == 0) {
RB_FOREACH(w, windows, &windows) { RB_FOREACH(w, windows, &windows) {
if (w->active == NULL)
continue;
if (options_get_number(w->options, "automatic-rename")) if (options_get_number(w->options, "automatic-rename"))
w->active->flags |= PANE_CHANGED; w->active->flags |= PANE_CHANGED;
} }
} }
if (strcmp(oe->name, "key-table") == 0) { if (strcmp(name, "key-table") == 0) {
TAILQ_FOREACH(c, &clients, entry) TAILQ_FOREACH(loop, &clients, entry)
server_client_set_key_table(c, NULL); server_client_set_key_table(loop, NULL);
} }
if (strcmp(oe->name, "status") == 0 || if (strcmp(name, "user-keys") == 0) {
strcmp(oe->name, "status-interval") == 0) TAILQ_FOREACH(loop, &clients, entry) {
if (loop->tty.flags & TTY_OPENED)
tty_keys_build(&loop->tty);
}
}
if (strcmp(name, "status-fg") == 0 || strcmp(name, "status-bg") == 0) {
sy = options_get_style(oo, "status-style");
sy->gc.fg = options_get_number(oo, "status-fg");
sy->gc.bg = options_get_number(oo, "status-bg");
}
if (strcmp(name, "status-style") == 0) {
sy = options_get_style(oo, "status-style");
options_set_number(oo, "status-fg", sy->gc.fg);
options_set_number(oo, "status-bg", sy->gc.bg);
}
if (strcmp(name, "status") == 0 ||
strcmp(name, "status-interval") == 0)
status_timer_start_all(); status_timer_start_all();
if (strcmp(oe->name, "monitor-silence") == 0) if (strcmp(name, "monitor-silence") == 0)
alerts_reset_all(); alerts_reset_all();
if (strcmp(oe->name, "window-style") == 0 || if (strcmp(name, "window-style") == 0 ||
strcmp(oe->name, "window-active-style") == 0) { strcmp(name, "window-active-style") == 0) {
RB_FOREACH(w, windows, &windows) RB_FOREACH(wp, window_pane_tree, &all_window_panes)
w->flags |= WINDOW_STYLECHANGED; wp->flags |= PANE_STYLECHANGED;
} }
if (strcmp(name, "pane-border-status") == 0) {
/* When the pane-border-status option has been changed, resize panes. */
if (strcmp(oe->name, "pane-border-status") == 0) {
RB_FOREACH(w, windows, &windows) RB_FOREACH(w, windows, &windows)
layout_fix_panes(w, w->sx, w->sy); layout_fix_panes(w);
} }
RB_FOREACH(s, sessions, &sessions)
status_update_cache(s);
/* Update sizes and redraw. May not need it but meh. */ /*
* Update sizes and redraw. May not always be necessary but do it
* anyway.
*/
recalculate_sizes(); recalculate_sizes();
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(loop, &clients, entry) {
if (c->session != NULL) if (loop->session != NULL)
server_redraw_client(c); server_redraw_client(loop);
} }
out:
free(argument);
free(value);
free(name);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
fail:
free(argument);
free(value);
free(name);
return (CMD_RETURN_ERROR);
} }
/* Set user option. */ static int
enum cmd_retval cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
cmd_set_option_user(struct cmd *self, struct cmd_q *cmdq, const char *optstr, struct options_entry *parent, const char *value)
const char *valstr)
{ {
struct args *args = self->args; const struct options_table_entry *oe;
struct session *s = cmdq->state.tflag.s; struct args *args = self->args;
struct winlink *wl = cmdq->state.tflag.wl; int append = args_has(args, 'a');
struct options *oo; struct options_entry *o;
struct options_entry *o; long long number;
const char *errstr, *new;
char *old;
key_code key;
if (args_has(args, 's')) oe = options_table_entry(parent);
oo = global_options; if (value == NULL &&
else if (args_has(self->args, 'w') || oe->type != OPTIONS_TABLE_FLAG &&
self->entry == &cmd_set_window_option_entry) { oe->type != OPTIONS_TABLE_CHOICE) {
if (args_has(self->args, 'g')) cmdq_error(item, "empty value");
oo = global_w_options;
else
oo = wl->window->options;
} else {
if (args_has(self->args, 'g'))
oo = global_s_options;
else
oo = s->options;
}
if (args_has(args, 'u')) {
if (options_find1(oo, optstr) == NULL) {
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "unknown option: %s", optstr);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
if (valstr != NULL) {
cmdq_error(cmdq, "value passed to unset option: %s",
optstr);
return (CMD_RETURN_ERROR);
}
options_remove(oo, optstr);
} else {
o = options_find1(oo, optstr);
if (args_has(args, 'o') && o != NULL) {
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "already set: %s", optstr);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
if (valstr == NULL) {
cmdq_error(cmdq, "empty value");
return (CMD_RETURN_ERROR);
}
if (o != NULL && args_has(args, 'a'))
options_set_string(oo, optstr, "%s%s", o->str, valstr);
else
options_set_string(oo, optstr, "%s", valstr);
}
return (CMD_RETURN_NORMAL);
}
/* Unset an option. */
int
cmd_set_option_unset(struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
struct args *args = self->args;
if (value != NULL) {
cmdq_error(cmdq, "value passed to unset option: %s", oe->name);
return (-1); return (-1);
} }
if (args_has(args, 'g') || oo == global_options) {
switch (oe->type) {
case OPTIONS_TABLE_STRING:
options_set_string(oo, oe->name, "%s", oe->default_str);
break;
case OPTIONS_TABLE_STYLE:
options_set_style(oo, oe->name, oe->default_str, 0);
break;
default:
options_set_number(oo, oe->name, oe->default_num);
break;
}
} else
options_remove(oo, oe->name);
return (0);
}
/* Set an option. */
int
cmd_set_option_set(struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
struct options_entry *o;
switch (oe->type) {
case OPTIONS_TABLE_FLAG:
case OPTIONS_TABLE_CHOICE:
break;
default:
if (value == NULL) {
cmdq_error(cmdq, "empty value");
return (-1);
}
}
o = NULL;
switch (oe->type) { switch (oe->type) {
case OPTIONS_TABLE_STRING: case OPTIONS_TABLE_STRING:
o = cmd_set_option_string(self, cmdq, oe, oo, value); old = xstrdup(options_get_string(oo, oe->name));
break; options_set_string(oo, oe->name, append, "%s", value);
new = options_get_string(oo, oe->name);
if (oe->pattern != NULL && fnmatch(oe->pattern, new, 0) != 0) {
options_set_string(oo, oe->name, 0, "%s", old);
free(old);
cmdq_error(item, "value is invalid: %s", value);
return (-1);
}
free(old);
return (0);
case OPTIONS_TABLE_NUMBER: case OPTIONS_TABLE_NUMBER:
o = cmd_set_option_number(self, cmdq, oe, oo, value); number = strtonum(value, oe->minimum, oe->maximum, &errstr);
break; if (errstr != NULL) {
cmdq_error(item, "value is %s: %s", errstr, value);
return (-1);
}
options_set_number(oo, oe->name, number);
return (0);
case OPTIONS_TABLE_KEY: case OPTIONS_TABLE_KEY:
o = cmd_set_option_key(self, cmdq, oe, oo, value); key = key_string_lookup_string(value);
break; if (key == KEYC_UNKNOWN) {
cmdq_error(item, "bad key: %s", value);
return (-1);
}
options_set_number(oo, oe->name, key);
return (0);
case OPTIONS_TABLE_COLOUR: case OPTIONS_TABLE_COLOUR:
o = cmd_set_option_colour(self, cmdq, oe, oo, value); if ((number = colour_fromstring(value)) == -1) {
if (o != NULL) cmdq_error(item, "bad colour: %s", value);
style_update_new(oo, o->name, oe->style); return (-1);
break; }
case OPTIONS_TABLE_ATTRIBUTES: options_set_number(oo, oe->name, number);
o = cmd_set_option_attributes(self, cmdq, oe, oo, value); return (0);
if (o != NULL)
style_update_new(oo, o->name, oe->style);
break;
case OPTIONS_TABLE_FLAG: case OPTIONS_TABLE_FLAG:
o = cmd_set_option_flag(self, cmdq, oe, oo, value); return (cmd_set_option_flag(item, oe, oo, value));
break;
case OPTIONS_TABLE_CHOICE: case OPTIONS_TABLE_CHOICE:
o = cmd_set_option_choice(self, cmdq, oe, oo, value); return (cmd_set_option_choice(item, oe, oo, value));
break;
case OPTIONS_TABLE_STYLE: case OPTIONS_TABLE_STYLE:
o = cmd_set_option_style(self, cmdq, oe, oo, value); o = options_set_style(oo, oe->name, append, value);
if (o == NULL) {
cmdq_error(item, "bad style: %s", value);
return (-1);
}
return (0);
case OPTIONS_TABLE_COMMAND:
break; break;
} }
if (o == NULL) return (-1);
return (-1);
return (0);
} }
/* Set a string option. */ static int
struct options_entry * cmd_set_option_flag(struct cmdq_item *item,
cmd_set_option_string(struct cmd *self, __unused struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
struct args *args = self->args;
struct options_entry *o;
char *oldval, *newval;
if (args_has(args, 'a')) {
oldval = options_get_string(oo, oe->name);
xasprintf(&newval, "%s%s", oldval, value);
} else
newval = xstrdup(value);
o = options_set_string(oo, oe->name, "%s", newval);
free(newval);
return (o);
}
/* Set a number option. */
struct options_entry *
cmd_set_option_number(__unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
long long ll;
const char *errstr;
ll = strtonum(value, oe->minimum, oe->maximum, &errstr);
if (errstr != NULL) {
cmdq_error(cmdq, "value is %s: %s", errstr, value);
return (NULL);
}
return (options_set_number(oo, oe->name, ll));
}
/* Set a key option. */
struct options_entry *
cmd_set_option_key(__unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
key_code key;
key = key_string_lookup_string(value);
if (key == KEYC_UNKNOWN) {
cmdq_error(cmdq, "bad key: %s", value);
return (NULL);
}
return (options_set_number(oo, oe->name, key));
}
/* Set a colour option. */
struct options_entry *
cmd_set_option_colour(__unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
int colour;
if ((colour = colour_fromstring(value)) == -1) {
cmdq_error(cmdq, "bad colour: %s", value);
return (NULL);
}
return (options_set_number(oo, oe->name, colour));
}
/* Set an attributes option. */
struct options_entry *
cmd_set_option_attributes(__unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
int attr;
if ((attr = attributes_fromstring(value)) == -1) {
cmdq_error(cmdq, "bad attributes: %s", value);
return (NULL);
}
return (options_set_number(oo, oe->name, attr));
}
/* Set a flag option. */
struct options_entry *
cmd_set_option_flag(__unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const struct options_table_entry *oe, struct options *oo,
const char *value) const char *value)
{ {
@@ -467,31 +366,28 @@ cmd_set_option_flag(__unused struct cmd *self, struct cmd_q *cmdq,
if (value == NULL || *value == '\0') if (value == NULL || *value == '\0')
flag = !options_get_number(oo, oe->name); flag = !options_get_number(oo, oe->name);
else if (strcmp(value, "1") == 0 ||
strcasecmp(value, "on") == 0 ||
strcasecmp(value, "yes") == 0)
flag = 1;
else if (strcmp(value, "0") == 0 ||
strcasecmp(value, "off") == 0 ||
strcasecmp(value, "no") == 0)
flag = 0;
else { else {
if ((value[0] == '1' && value[1] == '\0') || cmdq_error(item, "bad value: %s", value);
strcasecmp(value, "on") == 0 || return (-1);
strcasecmp(value, "yes") == 0)
flag = 1;
else if ((value[0] == '0' && value[1] == '\0') ||
strcasecmp(value, "off") == 0 ||
strcasecmp(value, "no") == 0)
flag = 0;
else {
cmdq_error(cmdq, "bad value: %s", value);
return (NULL);
}
} }
options_set_number(oo, oe->name, flag);
return (options_set_number(oo, oe->name, flag)); return (0);
} }
/* Set a choice option. */ static int
struct options_entry * cmd_set_option_choice(struct cmdq_item *item,
cmd_set_option_choice(__unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const struct options_table_entry *oe, struct options *oo,
const char *value) const char *value)
{ {
const char **choicep; const char **cp;
int n, choice = -1; int n, choice = -1;
if (value == NULL) { if (value == NULL) {
@@ -500,42 +396,16 @@ cmd_set_option_choice(__unused struct cmd *self, struct cmd_q *cmdq,
choice = !choice; choice = !choice;
} else { } else {
n = 0; n = 0;
for (choicep = oe->choices; *choicep != NULL; choicep++) { for (cp = oe->choices; *cp != NULL; cp++) {
if (strcmp(*cp, value) == 0)
choice = n;
n++; n++;
if (strncmp(*choicep, value, strlen(value)) != 0)
continue;
if (choice != -1) {
cmdq_error(cmdq, "ambiguous value: %s", value);
return (NULL);
}
choice = n - 1;
} }
if (choice == -1) { if (choice == -1) {
cmdq_error(cmdq, "unknown value: %s", value); cmdq_error(item, "unknown value: %s", value);
return (NULL); return (-1);
} }
} }
options_set_number(oo, oe->name, choice);
return (options_set_number(oo, oe->name, choice)); return (0);
}
/* Set a style option. */
struct options_entry *
cmd_set_option_style(struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
struct args *args = self->args;
struct options_entry *o;
int append;
append = args_has(args, 'a');
if ((o = options_set_style(oo, oe->name, value, append)) == NULL) {
cmdq_error(cmdq, "bad style: %s", value);
return (NULL);
}
style_update_old(oo, oe->name, &o->style);
return (o);
} }

View File

@@ -27,11 +27,12 @@
* Show environment. * Show environment.
*/ */
enum cmd_retval cmd_show_environment_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_show_environment_exec(struct cmd *,
struct cmdq_item *);
char *cmd_show_environment_escape(struct environ_entry *); static char *cmd_show_environment_escape(struct environ_entry *);
void cmd_show_environment_print(struct cmd *, struct cmd_q *, static void cmd_show_environment_print(struct cmd *, struct cmdq_item *,
struct environ_entry *); struct environ_entry *);
const struct cmd_entry cmd_show_environment_entry = { const struct cmd_entry cmd_show_environment_entry = {
.name = "show-environment", .name = "show-environment",
@@ -40,13 +41,13 @@ const struct cmd_entry cmd_show_environment_entry = {
.args = { "gst:", 0, 1 }, .args = { "gst:", 0, 1 },
.usage = "[-gs] " CMD_TARGET_SESSION_USAGE " [name]", .usage = "[-gs] " CMD_TARGET_SESSION_USAGE " [name]",
.tflag = CMD_SESSION_CANFAIL, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_show_environment_exec .exec = cmd_show_environment_exec
}; };
char * static char *
cmd_show_environment_escape(struct environ_entry *envent) cmd_show_environment_escape(struct environ_entry *envent)
{ {
const char *value = envent->value; const char *value = envent->value;
@@ -64,31 +65,31 @@ cmd_show_environment_escape(struct environ_entry *envent)
return (ret); return (ret);
} }
void static void
cmd_show_environment_print(struct cmd *self, struct cmd_q *cmdq, cmd_show_environment_print(struct cmd *self, struct cmdq_item *item,
struct environ_entry *envent) struct environ_entry *envent)
{ {
char *escaped; char *escaped;
if (!args_has(self->args, 's')) { if (!args_has(self->args, 's')) {
if (envent->value != NULL) if (envent->value != NULL)
cmdq_print(cmdq, "%s=%s", envent->name, envent->value); cmdq_print(item, "%s=%s", envent->name, envent->value);
else else
cmdq_print(cmdq, "-%s", envent->name); cmdq_print(item, "-%s", envent->name);
return; return;
} }
if (envent->value != NULL) { if (envent->value != NULL) {
escaped = cmd_show_environment_escape(envent); escaped = cmd_show_environment_escape(envent);
cmdq_print(cmdq, "%s=\"%s\"; export %s;", envent->name, escaped, cmdq_print(item, "%s=\"%s\"; export %s;", envent->name, escaped,
envent->name); envent->name);
free(escaped); free(escaped);
} else } else
cmdq_print(cmdq, "unset %s;", envent->name); cmdq_print(item, "unset %s;", envent->name);
} }
enum cmd_retval static enum cmd_retval
cmd_show_environment_exec(struct cmd *self, struct cmd_q *cmdq) cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct environ *env; struct environ *env;
@@ -96,8 +97,8 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_q *cmdq)
const char *target; const char *target;
if ((target = args_get(args, 't')) != NULL) { if ((target = args_get(args, 't')) != NULL) {
if (cmdq->state.tflag.s == NULL) { if (item->target.s == NULL) {
cmdq_error(cmdq, "no such session: %s", target); cmdq_error(item, "no such session: %s", target);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
@@ -105,30 +106,30 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(self->args, 'g')) if (args_has(self->args, 'g'))
env = global_environ; env = global_environ;
else { else {
if (cmdq->state.tflag.s == NULL) { if (item->target.s == NULL) {
target = args_get(args, 't'); target = args_get(args, 't');
if (target != NULL) if (target != NULL)
cmdq_error(cmdq, "no such session: %s", target); cmdq_error(item, "no such session: %s", target);
else else
cmdq_error(cmdq, "no current session"); cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
env = cmdq->state.tflag.s->environ; env = item->target.s->environ;
} }
if (args->argc != 0) { if (args->argc != 0) {
envent = environ_find(env, args->argv[0]); envent = environ_find(env, args->argv[0]);
if (envent == NULL) { if (envent == NULL) {
cmdq_error(cmdq, "unknown variable: %s", args->argv[0]); cmdq_error(item, "unknown variable: %s", args->argv[0]);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
cmd_show_environment_print(self, cmdq, envent); cmd_show_environment_print(self, item, envent);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
envent = environ_first(env); envent = environ_first(env);
while (envent != NULL) { while (envent != NULL) {
cmd_show_environment_print(self, cmdq, envent); cmd_show_environment_print(self, item, envent);
envent = environ_next(envent); envent = environ_next(envent);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -28,7 +28,8 @@
* Show client message log. * Show client message log.
*/ */
enum cmd_retval cmd_show_messages_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_show_messages_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_show_messages_entry = { const struct cmd_entry cmd_show_messages_entry = {
.name = "show-messages", .name = "show-messages",
@@ -37,28 +38,14 @@ const struct cmd_entry cmd_show_messages_entry = {
.args = { "JTt:", 0, 0 }, .args = { "JTt:", 0, 0 },
.usage = "[-JT] " CMD_TARGET_CLIENT_USAGE, .usage = "[-JT] " CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT, .flags = CMD_AFTERHOOK,
.flags = 0,
.exec = cmd_show_messages_exec .exec = cmd_show_messages_exec
}; };
const struct cmd_entry cmd_server_info_entry = { static int cmd_show_messages_terminals(struct cmdq_item *, int);
.name = "server-info",
.alias = "info",
.args = { "", 0, 0 }, static int
.usage = "", cmd_show_messages_terminals(struct cmdq_item *item, int blank)
.flags = 0,
.exec = cmd_show_messages_exec
};
int cmd_show_messages_terminals(struct cmd_q *, int);
int cmd_show_messages_jobs(struct cmd_q *, int);
int
cmd_show_messages_terminals(struct cmd_q *cmdq, int blank)
{ {
struct tty_term *term; struct tty_term *term;
u_int i, n; u_int i, n;
@@ -66,53 +53,37 @@ cmd_show_messages_terminals(struct cmd_q *cmdq, int blank)
n = 0; n = 0;
LIST_FOREACH(term, &tty_terms, entry) { LIST_FOREACH(term, &tty_terms, entry) {
if (blank) { if (blank) {
cmdq_print(cmdq, "%s", ""); cmdq_print(item, "%s", "");
blank = 0; blank = 0;
} }
cmdq_print(cmdq, "Terminal %u: %s [references=%u, flags=0x%x]:", cmdq_print(item, "Terminal %u: %s [references=%u, flags=0x%x]:",
n, term->name, term->references, term->flags); n, term->name, term->references, term->flags);
n++; n++;
for (i = 0; i < tty_term_ncodes(); i++) for (i = 0; i < tty_term_ncodes(); i++)
cmdq_print(cmdq, "%s", tty_term_describe(term, i)); cmdq_print(item, "%s", tty_term_describe(term, i));
} }
return (n != 0); return (n != 0);
} }
int static enum cmd_retval
cmd_show_messages_jobs(struct cmd_q *cmdq, int blank) cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
{
struct job *job;
u_int n;
n = 0;
LIST_FOREACH(job, &all_jobs, lentry) {
if (blank) {
cmdq_print(cmdq, "%s", "");
blank = 0;
}
cmdq_print(cmdq, "Job %u: %s [fd=%d, pid=%d, status=%d]",
n, job->cmd, job->fd, job->pid, job->status);
n++;
}
return (n != 0);
}
enum cmd_retval
cmd_show_messages_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmdq->state.c; struct client *c;
struct message_entry *msg; struct message_entry *msg;
char *tim; char *tim;
int done, blank; int done, blank;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
done = blank = 0; done = blank = 0;
if (args_has(args, 'T') || self->entry == &cmd_server_info_entry) { if (args_has(args, 'T')) {
blank = cmd_show_messages_terminals(cmdq, blank); blank = cmd_show_messages_terminals(item, blank);
done = 1; done = 1;
} }
if (args_has(args, 'J') || self->entry == &cmd_server_info_entry) { if (args_has(args, 'J')) {
cmd_show_messages_jobs(cmdq, blank); job_print_summary(item, blank);
done = 1; done = 1;
} }
if (done) if (done)
@@ -122,7 +93,7 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_q *cmdq)
tim = ctime(&msg->msg_time); tim = ctime(&msg->msg_time);
*strchr(tim, '\n') = '\0'; *strchr(tim, '\n') = '\0';
cmdq_print(cmdq, "%s %s", tim, msg->msg); cmdq_print(item, "%s %s", tim, msg->msg);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -27,23 +27,23 @@
* Show options. * Show options.
*/ */
enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmdq_item *);
enum cmd_retval cmd_show_options_one(struct cmd *, struct cmd_q *, static void cmd_show_options_print(struct cmd *, struct cmdq_item *,
struct options *, int); struct options_entry *, int, int);
enum cmd_retval cmd_show_options_all(struct cmd *, struct cmd_q *, static enum cmd_retval cmd_show_options_all(struct cmd *, struct cmdq_item *,
struct options *, enum options_table_scope); int, struct options *);
const struct cmd_entry cmd_show_options_entry = { const struct cmd_entry cmd_show_options_entry = {
.name = "show-options", .name = "show-options",
.alias = "show", .alias = "show",
.args = { "gqst:vw", 0, 1 }, .args = { "AgHpqst:vw", 0, 1 },
.usage = "[-gqsvw] [-t target-session|target-window] [option]", .usage = "[-AgHpqsvw] " CMD_TARGET_PANE_USAGE " [option]",
.tflag = CMD_WINDOW_CANFAIL, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec .exec = cmd_show_options_exec
}; };
@@ -54,144 +54,199 @@ const struct cmd_entry cmd_show_window_options_entry = {
.args = { "gvt:", 0, 1 }, .args = { "gvt:", 0, 1 },
.usage = "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]", .usage = "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]",
.tflag = CMD_WINDOW_CANFAIL, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec .exec = cmd_show_options_exec
}; };
enum cmd_retval const struct cmd_entry cmd_show_hooks_entry = {
cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq) .name = "show-hooks",
.alias = NULL,
.args = { "gt:", 0, 1 },
.usage = "[-g] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec
};
static enum cmd_retval
cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s = cmdq->state.tflag.s; struct cmd_find_state *fs = &item->target;
struct winlink *wl = cmdq->state.tflag.wl; struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct options *oo; struct options *oo;
enum options_table_scope scope; char *argument, *name = NULL, *cause;
int quiet; int window, idx, ambiguous, parent, scope;
const char *target; struct options_entry *o;
if (args_has(self->args, 's')) { window = (self->entry == &cmd_show_window_options_entry);
oo = global_options;
scope = OPTIONS_TABLE_SERVER;
} else if (args_has(self->args, 'w') ||
self->entry == &cmd_show_window_options_entry) {
scope = OPTIONS_TABLE_WINDOW;
if (args_has(self->args, 'g'))
oo = global_w_options;
else if (wl == NULL) {
target = args_get(args, 't');
if (target != NULL) {
cmdq_error(cmdq, "no such window: %s", target);
} else
cmdq_error(cmdq, "no current window");
return (CMD_RETURN_ERROR);
} else
oo = wl->window->options;
} else {
scope = OPTIONS_TABLE_SESSION;
if (args_has(self->args, 'g'))
oo = global_s_options;
else if (s == NULL) {
target = args_get(args, 't');
if (target != NULL) {
cmdq_error(cmdq, "no such session: %s", target);
} else
cmdq_error(cmdq, "no current session");
return (CMD_RETURN_ERROR);
} else
oo = s->options;
}
quiet = args_has(self->args, 'q'); if (args->argc == 0) {
if (args->argc == 0) scope = options_scope_from_flags(args, window, fs, &oo, &cause);
return (cmd_show_options_all(self, cmdq, oo, scope)); if (scope == OPTIONS_TABLE_NONE) {
else if (args_has(args, 'q'))
return (cmd_show_options_one(self, cmdq, oo, quiet));
}
enum cmd_retval
cmd_show_options_one(struct cmd *self, struct cmd_q *cmdq,
struct options *oo, int quiet)
{
struct args *args = self->args;
const char *name = args->argv[0];
const struct options_table_entry *oe;
struct options_entry *o;
const char *optval;
retry:
if (*name == '@') {
if ((o = options_find1(oo, name)) == NULL) {
if (quiet)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
cmdq_error(cmdq, "unknown option: %s", name); cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(self->args, 'v')) return (cmd_show_options_all(self, item, scope, oo));
cmdq_print(cmdq, "%s", o->str);
else
cmdq_print(cmdq, "%s \"%s\"", o->name, o->str);
return (CMD_RETURN_NORMAL);
} }
argument = format_single(item, args->argv[0], c, s, wl, NULL);
oe = NULL; name = options_match(argument, &idx, &ambiguous);
if (options_table_find(name, &oe) != 0) { if (name == NULL) {
cmdq_error(cmdq, "ambiguous option: %s", name); if (args_has(args, 'q'))
return (CMD_RETURN_ERROR); goto fail;
if (ambiguous)
cmdq_error(item, "ambiguous option: %s", argument);
else
cmdq_error(item, "invalid option: %s", argument);
goto fail;
} }
if (oe == NULL) { scope = options_scope_from_name(args, window, name, fs, &oo, &cause);
if (quiet) if (scope == OPTIONS_TABLE_NONE) {
return (CMD_RETURN_NORMAL); if (args_has(args, 'q'))
cmdq_error(cmdq, "unknown option: %s", name); goto fail;
return (CMD_RETURN_ERROR); cmdq_error(item, "%s", cause);
free(cause);
goto fail;
} }
if (oe->style != NULL) { o = options_get_only(oo, name);
name = oe->style; if (args_has(args, 'A') && o == NULL) {
goto retry; o = options_get(oo, name);
} parent = 1;
if ((o = options_find1(oo, oe->name)) == NULL) } else
return (CMD_RETURN_NORMAL); parent = 0;
optval = options_table_print_entry(oe, o, args_has(self->args, 'v')); if (o != NULL)
if (args_has(self->args, 'v')) cmd_show_options_print(self, item, o, idx, parent);
cmdq_print(cmdq, "%s", optval);
else free(name);
cmdq_print(cmdq, "%s %s", oe->name, optval); free(argument);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
fail:
free(name);
free(argument);
return (CMD_RETURN_ERROR);
} }
enum cmd_retval static void
cmd_show_options_all(struct cmd *self, struct cmd_q *cmdq, struct options *oo, cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
enum options_table_scope scope) struct options_entry *o, int idx, int parent)
{
struct options_array_item *a;
const char *name = options_name(o);
char *value, *tmp = NULL, *escaped;
if (idx != -1) {
xasprintf(&tmp, "%s[%d]", name, idx);
name = tmp;
} else {
if (options_isarray(o)) {
a = options_array_first(o);
if (a == NULL) {
if (!args_has(self->args, 'v'))
cmdq_print(item, "%s", name);
return;
}
while (a != NULL) {
idx = options_array_item_index(a);
cmd_show_options_print(self, item, o, idx,
parent);
a = options_array_next(a);
}
return;
}
}
value = options_tostring(o, idx, 0);
if (args_has(self->args, 'v'))
cmdq_print(item, "%s", value);
else if (options_isstring(o)) {
escaped = args_escape(value);
if (parent)
cmdq_print(item, "%s* %s", name, escaped);
else
cmdq_print(item, "%s %s", name, escaped);
free(escaped);
} else {
if (parent)
cmdq_print(item, "%s* %s", name, value);
else
cmdq_print(item, "%s %s", name, value);
}
free(value);
free(tmp);
}
static enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
struct options *oo)
{ {
const struct options_table_entry *oe; const struct options_table_entry *oe;
struct options_entry *o; struct options_entry *o;
const char *optval; struct options_array_item *a;
int vflag; const char *name;
u_int idx;
int parent;
o = options_first(oo); o = options_first(oo);
while (o != NULL) { while (o != NULL) {
if (*o->name == '@') { if (options_table_entry(o) == NULL)
if (args_has(self->args, 'v')) cmd_show_options_print(self, item, o, -1, 0);
cmdq_print(cmdq, "%s", o->str);
else
cmdq_print(cmdq, "%s \"%s\"", o->name, o->str);
}
o = options_next(o); o = options_next(o);
} }
vflag = args_has(self->args, 'v');
for (oe = options_table; oe->name != NULL; oe++) { for (oe = options_table; oe->name != NULL; oe++) {
if (oe->style != NULL || oe->scope != scope) if (~oe->scope & scope)
continue; continue;
if ((o = options_find1(oo, oe->name)) == NULL)
continue;
optval = options_table_print_entry(oe, o, vflag);
if (vflag)
cmdq_print(cmdq, "%s", optval);
else
cmdq_print(cmdq, "%s %s", oe->name, optval);
}
if ((self->entry != &cmd_show_hooks_entry &&
!args_has(self->args, 'H') &&
oe != NULL &&
(oe->flags & OPTIONS_TABLE_IS_HOOK)) ||
(self->entry == &cmd_show_hooks_entry &&
(oe == NULL ||
(~oe->flags & OPTIONS_TABLE_IS_HOOK))))
continue;
o = options_get_only(oo, oe->name);
if (o == NULL) {
if (!args_has(self->args, 'A'))
continue;
o = options_get(oo, oe->name);
if (o == NULL)
continue;
parent = 1;
} else
parent = 0;
if (!options_isarray(o))
cmd_show_options_print(self, item, o, -1, parent);
else if ((a = options_array_first(o)) == NULL) {
if (!args_has(self->args, 'v')) {
name = options_name(o);
if (parent)
cmdq_print(item, "%s*", name);
else
cmdq_print(item, "%s", name);
}
} else {
while (a != NULL) {
idx = options_array_item_index(a);
cmd_show_options_print(self, item, o, idx,
parent);
a = options_array_next(a);
}
}
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -18,7 +18,10 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h>
#include <glob.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -26,72 +29,87 @@
* Sources a configuration file. * Sources a configuration file.
*/ */
enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmdq_item *);
void cmd_source_file_done(struct cmd_q *); static enum cmd_retval cmd_source_file_done(struct cmdq_item *, void *);
const struct cmd_entry cmd_source_file_entry = { const struct cmd_entry cmd_source_file_entry = {
.name = "source-file", .name = "source-file",
.alias = "source", .alias = "source",
.args = { "q", 1, 1 }, .args = { "nqv", 1, -1 },
.usage = "[-q] path", .usage = "[-nqv] path ...",
.flags = 0, .flags = 0,
.exec = cmd_source_file_exec .exec = cmd_source_file_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq) cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_q *cmdq1; int flags = 0;
int quiet; struct client *c = item->client;
struct cmdq_item *new_item, *after;
enum cmd_retval retval;
char *pattern, *cwd;
const char *path, *error;
glob_t g;
int i;
u_int j;
cmdq1 = cmdq_new(cmdq->client); if (args_has(args, 'q'))
cmdq1->flags |= cmdq->flags & CMD_Q_NOHOOKS; flags |= CMD_PARSE_QUIET;
cmdq1->emptyfn = cmd_source_file_done; if (args_has(args, 'n'))
cmdq1->data = cmdq; flags |= CMD_PARSE_PARSEONLY;
if (args_has(args, 'v'))
flags |= CMD_PARSE_VERBOSE;
utf8_stravis(&cwd, server_client_get_cwd(c, NULL), VIS_GLOB);
quiet = args_has(args, 'q'); retval = CMD_RETURN_NORMAL;
switch (load_cfg(args->argv[0], cmdq1, quiet)) { for (i = 0; i < args->argc; i++) {
case -1: path = args->argv[i];
cmdq_free(cmdq1); if (*path == '/')
if (cfg_references == 0) { pattern = xstrdup(path);
cfg_print_causes(cmdq); else
return (CMD_RETURN_ERROR); xasprintf(&pattern, "%s/%s", cwd, path);
log_debug("%s: %s", __func__, pattern);
if (glob(pattern, 0, NULL, &g) != 0) {
error = strerror(errno);
if (errno != ENOENT || (~flags & CMD_PARSE_QUIET)) {
cmdq_error(item, "%s: %s", path, error);
retval = CMD_RETURN_ERROR;
}
free(pattern);
continue;
} }
return (CMD_RETURN_NORMAL); free(pattern);
case 0:
cmdq_free(cmdq1); after = item;
if (cfg_references == 0) for (j = 0; j < g.gl_pathc; j++) {
cfg_print_causes(cmdq); path = g.gl_pathv[j];
return (CMD_RETURN_NORMAL); if (load_cfg(path, c, after, flags, &new_item) < 0)
retval = CMD_RETURN_ERROR;
else if (new_item != NULL)
after = new_item;
}
globfree(&g);
}
if (cfg_finished) {
if (retval == CMD_RETURN_ERROR && c->session == NULL)
c->retval = 1;
new_item = cmdq_get_callback(cmd_source_file_done, NULL);
cmdq_insert_after(item, new_item);
} }
cmdq->references++; free(cwd);
cfg_references++; return (retval);
cmdq_continue(cmdq1);
return (CMD_RETURN_WAIT);
} }
void static enum cmd_retval
cmd_source_file_done(struct cmd_q *cmdq1) cmd_source_file_done(struct cmdq_item *item, __unused void *data)
{ {
struct cmd_q *cmdq = cmdq1->data; cfg_print_causes(item);
return (CMD_RETURN_NORMAL);
if (cmdq1->client_exit >= 0)
cmdq->client_exit = cmdq1->client_exit;
cmdq_free(cmdq1);
cfg_references--;
if (cmdq_free(cmdq))
return;
if (cfg_references == 0)
cfg_print_causes(cmdq);
cmdq_continue(cmdq);
} }

View File

@@ -32,165 +32,141 @@
#define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" #define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_split_window_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_split_window_entry = { const struct cmd_entry cmd_split_window_entry = {
.name = "split-window", .name = "split-window",
.alias = "splitw", .alias = "splitw",
.args = { "bc:dfF:l:hp:Pt:v", 0, -1 }, .args = { "bc:de:fF:hIl:p:Pt:v", 0, -1 },
.usage = "[-bdfhvP] [-c start-directory] [-F format] " .usage = "[-bdefhIPv] [-c start-directory] [-e environment] "
"[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]", "[-F format] [-p percentage|-l size] " CMD_TARGET_PANE_USAGE
" [command]",
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_split_window_exec .exec = cmd_split_window_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s = cmdq->state.tflag.s; struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = cmdq->state.tflag.wl; struct spawn_context sc;
struct window *w = wl->window; struct client *c = cmd_find_client(item, NULL, 1);
struct window_pane *wp = cmdq->state.tflag.wp, *new_wp = NULL; struct session *s = item->target.s;
struct environ *env; struct winlink *wl = item->target.wl;
const char *cmd, *path, *shell, *template, *cwd, *to_free; struct window_pane *wp = item->target.wp, *new_wp;
char **argv, *cause, *new_cause, *cp;
u_int hlimit;
int argc, size, percentage;
enum layout_type type; enum layout_type type;
struct layout_cell *lc; struct layout_cell *lc;
struct format_tree *ft; struct cmd_find_state fs;
struct environ_entry *envent; int size, percentage, flags, input;
const char *template, *add;
char *cause, *cp;
struct args_value *value;
server_unzoom_window(w);
env = environ_create();
environ_copy(global_environ, env);
environ_copy(s->environ, env);
server_fill_environ(s, env);
if (args->argc == 0) {
cmd = options_get_string(s->options, "default-command");
if (cmd != NULL && *cmd != '\0') {
argc = 1;
argv = (char **)&cmd;
} else {
argc = 0;
argv = NULL;
}
} else {
argc = args->argc;
argv = args->argv;
}
to_free = NULL;
if (args_has(args, 'c')) {
ft = format_create(cmdq, 0);
format_defaults(ft, cmdq->state.c, s, NULL, NULL);
to_free = cwd = format_expand(ft, args_get(args, 'c'));
format_free(ft);
} else if (cmdq->client != NULL && cmdq->client->session == NULL)
cwd = cmdq->client->cwd;
else
cwd = s->cwd;
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h')) if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT; type = LAYOUT_LEFTRIGHT;
else
size = -1; type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'l')) { if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause); size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) { if (cause != NULL) {
xasprintf(&new_cause, "size %s", cause); cmdq_error(item, "create pane failed: -l %s", cause);
free(cause); free(cause);
cause = new_cause; return (CMD_RETURN_ERROR);
goto error;
} }
} else if (args_has(args, 'p')) { } else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause); percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
if (cause != NULL) { if (cause != NULL) {
xasprintf(&new_cause, "percentage %s", cause); cmdq_error(item, "create pane failed: -p %s", cause);
free(cause); free(cause);
cause = new_cause; return (CMD_RETURN_ERROR);
goto error;
} }
if (type == LAYOUT_TOPBOTTOM) if (type == LAYOUT_TOPBOTTOM)
size = (wp->sy * percentage) / 100; size = (wp->sy * percentage) / 100;
else else
size = (wp->sx * percentage) / 100; size = (wp->sx * percentage) / 100;
}
hlimit = options_get_number(s->options, "history-limit");
shell = options_get_string(s->options, "default-shell");
if (*shell == '\0' || areshell(shell))
shell = _PATH_BSHELL;
lc = layout_split_pane(wp, type, size, args_has(args, 'b'),
args_has(args, 'f'));
if (lc == NULL) {
cause = xstrdup("pane too small");
goto error;
}
new_wp = window_add_pane(w, wp, hlimit);
layout_assign_pane(lc, new_wp);
path = NULL;
if (cmdq->client != NULL && cmdq->client->session == NULL)
envent = environ_find(cmdq->client->environ, "PATH");
else
envent = environ_find(s->environ, "PATH");
if (envent != NULL)
path = envent->value;
if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, env,
s->tio, &cause) != 0)
goto error;
server_redraw_window(w);
if (!args_has(args, 'd')) {
window_set_active_pane(w, new_wp);
session_select(s, wl->idx);
server_redraw_session(s);
} else } else
server_status_session(s); size = -1;
environ_free(env); server_unzoom_window(wp->window);
input = (args_has(args, 'I') && args->argc == 0);
flags = 0;
if (args_has(args, 'b'))
flags |= SPAWN_BEFORE;
if (args_has(args, 'f'))
flags |= SPAWN_FULLSIZE;
if (input || (args->argc == 1 && *args->argv[0] == '\0'))
flags |= SPAWN_EMPTY;
lc = layout_split_pane(wp, type, size, flags);
if (lc == NULL) {
cmdq_error(item, "no space for new pane");
return (CMD_RETURN_ERROR);
}
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
sc.wl = wl;
sc.wp0 = wp;
sc.lc = lc;
sc.name = NULL;
sc.argc = args->argc;
sc.argv = args->argv;
sc.environ = environ_create();
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
add = args_next_value(&value);
}
sc.idx = -1;
sc.cwd = args_get(args, 'c');
sc.flags = flags;
if (args_has(args, 'd'))
sc.flags |= SPAWN_DETACHED;
if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
layout_close_pane(new_wp);
cmdq_error(item, "create pane failed: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (input && window_pane_start_input(new_wp, item, &cause) != 0) {
layout_close_pane(new_wp);
window_remove_pane(wp->window, new_wp);
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (!args_has(args, 'd'))
cmd_find_from_winlink_pane(current, wl, new_wp, 0);
server_redraw_window(wp->window);
server_status_session(s);
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = SPLIT_WINDOW_TEMPLATE; template = SPLIT_WINDOW_TEMPLATE;
cp = format_single(item, template, c, s, wl, new_wp);
ft = format_create(cmdq, 0); cmdq_print(item, "%s", cp);
format_defaults(ft, cmdq->state.c, s, wl, new_wp);
cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp);
free(cp); free(cp);
format_free(ft);
} }
notify_window_layout_changed(w);
if (to_free != NULL) cmd_find_from_winlink_pane(&fs, wl, new_wp, 0);
free((void *)to_free); cmdq_insert_hook(s, item, &fs, "after-split-window");
environ_free(sc.environ);
if (input)
return (CMD_RETURN_WAIT);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
error:
environ_free(env);
if (new_wp != NULL) {
layout_close_pane(new_wp);
window_remove_pane(w, new_wp);
}
cmdq_error(cmdq, "create pane failed: %s", cause);
free(cause);
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_ERROR);
} }

View File

@@ -1,359 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "tmux.h"
/*
* Parse a command from a string.
*/
int cmd_string_getc(const char *, size_t *);
void cmd_string_ungetc(size_t *);
void cmd_string_copy(char **, char *, size_t *);
char *cmd_string_string(const char *, size_t *, char, int);
char *cmd_string_variable(const char *, size_t *);
char *cmd_string_expand_tilde(const char *, size_t *);
int
cmd_string_getc(const char *s, size_t *p)
{
const u_char *ucs = s;
if (ucs[*p] == '\0')
return (EOF);
return (ucs[(*p)++]);
}
void
cmd_string_ungetc(size_t *p)
{
(*p)--;
}
/*
* Parse command string. Returns -1 on error. If returning -1, cause is error
* string, or NULL for empty command.
*/
int
cmd_string_parse(const char *s, struct cmd_list **cmdlist, const char *file,
u_int line, char **cause)
{
size_t p;
int ch, i, argc, rval;
char **argv, *buf, *t;
const char *whitespace, *equals;
size_t len;
argv = NULL;
argc = 0;
buf = NULL;
len = 0;
*cause = NULL;
*cmdlist = NULL;
rval = -1;
p = 0;
for (;;) {
ch = cmd_string_getc(s, &p);
switch (ch) {
case '\'':
if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL)
goto error;
cmd_string_copy(&buf, t, &len);
break;
case '"':
if ((t = cmd_string_string(s, &p, '"', 1)) == NULL)
goto error;
cmd_string_copy(&buf, t, &len);
break;
case '$':
if ((t = cmd_string_variable(s, &p)) == NULL)
goto error;
cmd_string_copy(&buf, t, &len);
break;
case '#':
/* Comment: discard rest of line. */
while ((ch = cmd_string_getc(s, &p)) != EOF)
;
/* FALLTHROUGH */
case EOF:
case ' ':
case '\t':
if (buf != NULL) {
buf = xrealloc(buf, len + 1);
buf[len] = '\0';
argv = xreallocarray(argv, argc + 1,
sizeof *argv);
argv[argc++] = buf;
buf = NULL;
len = 0;
}
if (ch != EOF)
break;
while (argc != 0) {
equals = strchr(argv[0], '=');
whitespace = argv[0] + strcspn(argv[0], " \t");
if (equals == NULL || equals > whitespace)
break;
environ_put(global_environ, argv[0]);
argc--;
memmove(argv, argv + 1, argc * (sizeof *argv));
}
if (argc == 0)
goto out;
*cmdlist = cmd_list_parse(argc, argv, file, line, cause);
if (*cmdlist == NULL)
goto out;
rval = 0;
goto out;
case '~':
if (buf == NULL) {
t = cmd_string_expand_tilde(s, &p);
if (t == NULL)
goto error;
cmd_string_copy(&buf, t, &len);
break;
}
/* FALLTHROUGH */
default:
if (len >= SIZE_MAX - 2)
goto error;
buf = xrealloc(buf, len + 1);
buf[len++] = ch;
break;
}
}
error:
xasprintf(cause, "invalid or unknown command: %s", s);
out:
free(buf);
if (argv != NULL) {
for (i = 0; i < argc; i++)
free(argv[i]);
free(argv);
}
return (rval);
}
void
cmd_string_copy(char **dst, char *src, size_t *len)
{
size_t srclen;
srclen = strlen(src);
*dst = xrealloc(*dst, *len + srclen + 1);
strlcpy(*dst + *len, src, srclen + 1);
*len += srclen;
free(src);
}
char *
cmd_string_string(const char *s, size_t *p, char endch, int esc)
{
int ch;
char *buf, *t;
size_t len;
buf = NULL;
len = 0;
while ((ch = cmd_string_getc(s, p)) != endch) {
switch (ch) {
case EOF:
goto error;
case '\\':
if (!esc)
break;
switch (ch = cmd_string_getc(s, p)) {
case EOF:
goto error;
case 'e':
ch = '\033';
break;
case 'r':
ch = '\r';
break;
case 'n':
ch = '\n';
break;
case 't':
ch = '\t';
break;
}
break;
case '$':
if (!esc)
break;
if ((t = cmd_string_variable(s, p)) == NULL)
goto error;
cmd_string_copy(&buf, t, &len);
continue;
}
if (len >= SIZE_MAX - 2)
goto error;
buf = xrealloc(buf, len + 1);
buf[len++] = ch;
}
buf = xrealloc(buf, len + 1);
buf[len] = '\0';
return (buf);
error:
free(buf);
return (NULL);
}
char *
cmd_string_variable(const char *s, size_t *p)
{
int ch, fch;
char *buf, *t;
size_t len;
struct environ_entry *envent;
#define cmd_string_first(ch) ((ch) == '_' || \
((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
#define cmd_string_other(ch) ((ch) == '_' || \
((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
((ch) >= '0' && (ch) <= '9'))
buf = NULL;
len = 0;
fch = EOF;
switch (ch = cmd_string_getc(s, p)) {
case EOF:
goto error;
case '{':
fch = '{';
ch = cmd_string_getc(s, p);
if (!cmd_string_first(ch))
goto error;
/* FALLTHROUGH */
default:
if (!cmd_string_first(ch)) {
xasprintf(&t, "$%c", ch);
return (t);
}
buf = xrealloc(buf, len + 1);
buf[len++] = ch;
for (;;) {
ch = cmd_string_getc(s, p);
if (ch == EOF || !cmd_string_other(ch))
break;
else {
if (len >= SIZE_MAX - 3)
goto error;
buf = xrealloc(buf, len + 1);
buf[len++] = ch;
}
}
}
if (fch == '{' && ch != '}')
goto error;
if (ch != EOF && fch != '{')
cmd_string_ungetc(p); /* ch */
buf = xrealloc(buf, len + 1);
buf[len] = '\0';
envent = environ_find(global_environ, buf);
free(buf);
if (envent == NULL)
return (xstrdup(""));
return (xstrdup(envent->value));
error:
free(buf);
return (NULL);
}
char *
cmd_string_expand_tilde(const char *s, size_t *p)
{
struct passwd *pw;
struct environ_entry *envent;
char *home, *path, *user, *cp;
int last;
home = NULL;
last = cmd_string_getc(s, p);
if (last == EOF || last == '/' || last == ' '|| last == '\t') {
envent = environ_find(global_environ, "HOME");
if (envent != NULL && *envent->value != '\0')
home = envent->value;
else if ((pw = getpwuid(getuid())) != NULL)
home = pw->pw_dir;
} else {
cmd_string_ungetc(p);
cp = user = xmalloc(strlen(s));
for (;;) {
last = cmd_string_getc(s, p);
if (last == EOF || last == '/' || last == ' '|| last == '\t')
break;
*cp++ = last;
}
*cp = '\0';
if ((pw = getpwnam(user)) != NULL)
home = pw->pw_dir;
free(user);
}
if (home == NULL)
return (NULL);
if (last != EOF)
xasprintf(&path, "%s%c", home, last);
else
xasprintf(&path, "%s", home);
return (path);
}

View File

@@ -26,7 +26,7 @@
* Swap two panes. * Swap two panes.
*/ */
enum cmd_retval cmd_swap_pane_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_swap_pane_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_swap_pane_entry = { const struct cmd_entry cmd_swap_pane_entry = {
.name = "swap-pane", .name = "swap-pane",
@@ -35,25 +35,25 @@ const struct cmd_entry cmd_swap_pane_entry = {
.args = { "dDs:t:U", 0, 0 }, .args = { "dDs:t:U", 0, 0 },
.usage = "[-dDU] " CMD_SRCDST_PANE_USAGE, .usage = "[-dDU] " CMD_SRCDST_PANE_USAGE,
.sflag = CMD_PANE_MARKED, .source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_swap_pane_exec .exec = cmd_swap_pane_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct window *src_w, *dst_w; struct window *src_w, *dst_w;
struct window_pane *tmp_wp, *src_wp, *dst_wp; struct window_pane *tmp_wp, *src_wp, *dst_wp;
struct layout_cell *src_lc, *dst_lc; struct layout_cell *src_lc, *dst_lc;
u_int sx, sy, xoff, yoff; u_int sx, sy, xoff, yoff;
dst_w = cmdq->state.tflag.wl->window; dst_w = item->target.wl->window;
dst_wp = cmdq->state.tflag.wp; dst_wp = item->target.wp;
src_w = cmdq->state.sflag.wl->window; src_w = item->source.wl->window;
src_wp = cmdq->state.sflag.wp; src_wp = item->source.wp;
server_unzoom_window(dst_w); server_unzoom_window(dst_w);
if (args_has(self->args, 'D')) { if (args_has(self->args, 'D')) {
@@ -90,7 +90,11 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq)
src_wp->layout_cell = dst_lc; src_wp->layout_cell = dst_lc;
src_wp->window = dst_w; src_wp->window = dst_w;
options_set_parent(src_wp->options, dst_w->options);
src_wp->flags |= PANE_STYLECHANGED;
dst_wp->window = src_w; dst_wp->window = src_w;
options_set_parent(dst_wp->options, src_w->options);
dst_wp->flags |= PANE_STYLECHANGED;
sx = src_wp->sx; sy = src_wp->sy; sx = src_wp->sx; sy = src_wp->sy;
xoff = src_wp->xoff; yoff = src_wp->yoff; xoff = src_wp->xoff; yoff = src_wp->yoff;
@@ -101,19 +105,17 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq)
if (!args_has(self->args, 'd')) { if (!args_has(self->args, 'd')) {
if (src_w != dst_w) { if (src_w != dst_w) {
window_set_active_pane(src_w, dst_wp); window_set_active_pane(src_w, dst_wp, 1);
window_set_active_pane(dst_w, src_wp); window_set_active_pane(dst_w, src_wp, 1);
} else { } else {
tmp_wp = dst_wp; tmp_wp = dst_wp;
if (!window_pane_visible(tmp_wp)) window_set_active_pane(src_w, tmp_wp, 1);
tmp_wp = src_wp;
window_set_active_pane(src_w, tmp_wp);
} }
} else { } else {
if (src_w->active == src_wp) if (src_w->active == src_wp)
window_set_active_pane(src_w, dst_wp); window_set_active_pane(src_w, dst_wp, 1);
if (dst_w->active == dst_wp) if (dst_w->active == dst_wp)
window_set_active_pane(dst_w, src_wp); window_set_active_pane(dst_w, src_wp, 1);
} }
if (src_w != dst_w) { if (src_w != dst_w) {
if (src_w->last == src_wp) if (src_w->last == src_wp)

View File

@@ -26,7 +26,7 @@
* Swap one window with another. * Swap one window with another.
*/ */
enum cmd_retval cmd_swap_window_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_swap_window_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_swap_window_entry = { const struct cmd_entry cmd_swap_window_entry = {
.name = "swap-window", .name = "swap-window",
@@ -35,43 +35,49 @@ const struct cmd_entry cmd_swap_window_entry = {
.args = { "ds:t:", 0, 0 }, .args = { "ds:t:", 0, 0 },
.usage = "[-d] " CMD_SRCDST_WINDOW_USAGE, .usage = "[-d] " CMD_SRCDST_WINDOW_USAGE,
.sflag = CMD_WINDOW_MARKED, .source = { 's', CMD_FIND_WINDOW, CMD_FIND_DEFAULT_MARKED },
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_swap_window_exec .exec = cmd_swap_window_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_swap_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct session *src, *dst; struct session *src, *dst;
struct session_group *sg_src, *sg_dst; struct session_group *sg_src, *sg_dst;
struct winlink *wl_src, *wl_dst; struct winlink *wl_src, *wl_dst;
struct window *w; struct window *w_src, *w_dst;
wl_src = cmdq->state.sflag.wl; wl_src = item->source.wl;
src = cmdq->state.sflag.s; src = item->source.s;
sg_src = session_group_find(src); sg_src = session_group_contains(src);
wl_dst = cmdq->state.tflag.wl; wl_dst = item->target.wl;
dst = cmdq->state.tflag.s; dst = item->target.s;
sg_dst = session_group_find(dst); sg_dst = session_group_contains(dst);
if (src != dst && sg_src != NULL && sg_dst != NULL && if (src != dst && sg_src != NULL && sg_dst != NULL &&
sg_src == sg_dst) { sg_src == sg_dst) {
cmdq_error(cmdq, "can't move window, sessions are grouped"); cmdq_error(item, "can't move window, sessions are grouped");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (wl_dst->window == wl_src->window) if (wl_dst->window == wl_src->window)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
w = wl_dst->window; w_dst = wl_dst->window;
wl_dst->window = wl_src->window; TAILQ_REMOVE(&w_dst->winlinks, wl_dst, wentry);
wl_src->window = w; w_src = wl_src->window;
TAILQ_REMOVE(&w_src->winlinks, wl_src, wentry);
if (!args_has(self->args, 'd')) { wl_dst->window = w_src;
TAILQ_INSERT_TAIL(&w_src->winlinks, wl_dst, wentry);
wl_src->window = w_dst;
TAILQ_INSERT_TAIL(&w_dst->winlinks, wl_src, wentry);
if (args_has(self->args, 'd')) {
session_select(dst, wl_dst->idx); session_select(dst, wl_dst->idx);
if (src != dst) if (src != dst)
session_select(src, wl_src->idx); session_select(src, wl_src->idx);

View File

@@ -27,7 +27,8 @@
* Switch client to a different session. * Switch client to a different session.
*/ */
enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_switch_client_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_switch_client_entry = { const struct cmd_entry cmd_switch_client_entry = {
.name = "switch-client", .name = "switch-client",
@@ -37,24 +38,42 @@ const struct cmd_entry cmd_switch_client_entry = {
.usage = "[-Elnpr] [-c target-client] [-t target-session] " .usage = "[-Elnpr] [-c target-client] [-t target-session] "
"[-T key-table]", "[-T key-table]",
.cflag = CMD_CLIENT, /* -t is special */
.tflag = CMD_SESSION_WITHPANE,
.flags = CMD_READONLY, .flags = CMD_READONLY,
.exec = cmd_switch_client_exec .exec = cmd_switch_client_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq) cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_state *state = &cmdq->state; const char *tflag = args_get(args, 't');
struct client *c = state->c; enum cmd_find_type type;
struct session *s = cmdq->state.tflag.s; int flags;
struct client *c;
struct session *s;
struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
const char *tablename, *update; const char *tablename;
struct key_table *table; struct key_table *table;
if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (tflag != NULL && tflag[strcspn(tflag, ":.%")] != '\0') {
type = CMD_FIND_PANE;
flags = 0;
} else {
type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED;
}
if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR);
s = item->target.s;
wl = item->target.wl;
wp = item->target.wp;
if (args_has(args, 'r')) if (args_has(args, 'r'))
c->flags ^= CLIENT_READONLY; c->flags ^= CLIENT_READONLY;
@@ -62,7 +81,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
if (tablename != NULL) { if (tablename != NULL) {
table = key_bindings_get_table(tablename, 0); table = key_bindings_get_table(tablename, 0);
if (table == NULL) { if (table == NULL) {
cmdq_error(cmdq, "table %s doesn't exist", tablename); cmdq_error(item, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
table->references++; table->references++;
@@ -73,12 +92,12 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(args, 'n')) { if (args_has(args, 'n')) {
if ((s = session_next_session(c->session)) == NULL) { if ((s = session_next_session(c->session)) == NULL) {
cmdq_error(cmdq, "can't find next session"); cmdq_error(item, "can't find next session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else if (args_has(args, 'p')) { } else if (args_has(args, 'p')) {
if ((s = session_previous_session(c->session)) == NULL) { if ((s = session_previous_session(c->session)) == NULL) {
cmdq_error(cmdq, "can't find previous session"); cmdq_error(item, "can't find previous session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else if (args_has(args, 'l')) { } else if (args_has(args, 'l')) {
@@ -87,30 +106,34 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
else else
s = NULL; s = NULL;
if (s == NULL) { if (s == NULL) {
cmdq_error(cmdq, "can't find last session"); cmdq_error(item, "can't find last session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else { } else {
if (cmdq->client == NULL) if (item->client == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (state->tflag.wl != NULL) { if (wl != NULL) {
wp = state->tflag.wp; server_unzoom_window(wl->window);
if (wp != NULL) if (wp != NULL) {
window_set_active_pane(wp->window, wp); window_redraw_active_switch(wp->window, wp);
session_set_current(s, state->tflag.wl); window_set_active_pane(wp->window, wp, 1);
}
session_set_current(s, wl);
cmd_find_from_session(&item->shared->current, s, 0);
} }
} }
if (c != NULL && !args_has(args, 'E')) { if (!args_has(args, 'E'))
update = options_get_string(s->options, "update-environment"); environ_update(s->options, c->environ, s->environ);
environ_update(update, c->environ, s->environ);
}
if (c->session != NULL && c->session != s) if (c->session != NULL && c->session != s)
c->last_session = c->session; c->last_session = c->session;
c->session = s; c->session = s;
server_client_set_key_table(c, NULL); if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c); status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL); session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL); gettimeofday(&s->last_attached_time, NULL);

View File

@@ -26,23 +26,21 @@
* Unbind key from command. * Unbind key from command.
*/ */
enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmdq_item *);
enum cmd_retval cmd_unbind_key_mode_table(struct cmd *, struct cmd_q *,
key_code);
const struct cmd_entry cmd_unbind_key_entry = { const struct cmd_entry cmd_unbind_key_entry = {
.name = "unbind-key", .name = "unbind-key",
.alias = "unbind", .alias = "unbind",
.args = { "acnt:T:", 0, 1 }, .args = { "anT:", 0, 1 },
.usage = "[-acn] [-t mode-table] [-T key-table] key", .usage = "[-an] [-T key-table] key",
.flags = 0, .flags = CMD_AFTERHOOK,
.exec = cmd_unbind_key_exec .exec = cmd_unbind_key_exec
}; };
enum cmd_retval static enum cmd_retval
cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) cmd_unbind_key_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
key_code key; key_code key;
@@ -50,25 +48,22 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
if (!args_has(args, 'a')) { if (!args_has(args, 'a')) {
if (args->argc != 1) { if (args->argc != 1) {
cmdq_error(cmdq, "missing key"); cmdq_error(item, "missing key");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
key = key_string_lookup_string(args->argv[0]); key = key_string_lookup_string(args->argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) { if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
cmdq_error(cmdq, "unknown key: %s", args->argv[0]); cmdq_error(item, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else { } else {
if (args->argc != 0) { if (args->argc != 0) {
cmdq_error(cmdq, "key given with -a"); cmdq_error(item, "key given with -a");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
key = KEYC_UNKNOWN; key = KEYC_UNKNOWN;
} }
if (args_has(args, 't'))
return (cmd_unbind_key_mode_table(self, cmdq, key));
if (key == KEYC_UNKNOWN) { if (key == KEYC_UNKNOWN) {
tablename = args_get(args, 'T'); tablename = args_get(args, 'T');
if (tablename == NULL) { if (tablename == NULL) {
@@ -77,7 +72,7 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (key_bindings_get_table(tablename, 0) == NULL) { if (key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(cmdq, "table %s doesn't exist", tablename); cmdq_error(item, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
key_bindings_remove_table(tablename); key_bindings_remove_table(tablename);
@@ -87,7 +82,7 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(args, 'T')) { if (args_has(args, 'T')) {
tablename = args_get(args, 'T'); tablename = args_get(args, 'T');
if (key_bindings_get_table(tablename, 0) == NULL) { if (key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(cmdq, "table %s doesn't exist", tablename); cmdq_error(item, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else if (args_has(args, 'n')) } else if (args_has(args, 'n'))
@@ -97,35 +92,3 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
key_bindings_remove(tablename, key); key_bindings_remove(tablename, key);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
enum cmd_retval
cmd_unbind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, key_code key)
{
struct args *args = self->args;
const char *tablename;
const struct mode_key_table *mtab;
struct mode_key_binding *mbind, mtmp;
tablename = args_get(args, 't');
if ((mtab = mode_key_findtable(tablename)) == NULL) {
cmdq_error(cmdq, "unknown key table: %s", tablename);
return (CMD_RETURN_ERROR);
}
if (key == KEYC_UNKNOWN) {
while (!RB_EMPTY(mtab->tree)) {
mbind = RB_ROOT(mtab->tree);
RB_REMOVE(mode_key_tree, mtab->tree, mbind);
free(mbind);
}
return (CMD_RETURN_NORMAL);
}
mtmp.key = key;
mtmp.mode = !!args_has(args, 'c');
if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) {
RB_REMOVE(mode_key_tree, mtab->tree, mbind);
free(mbind);
}
return (CMD_RETURN_NORMAL);
}

View File

@@ -28,7 +28,7 @@
* Block or wake a client on a named wait channel. * Block or wake a client on a named wait channel.
*/ */
enum cmd_retval cmd_wait_for_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_wait_for_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_wait_for_entry = { const struct cmd_entry cmd_wait_for_entry = {
.name = "wait-for", .name = "wait-for",
@@ -41,42 +41,46 @@ const struct cmd_entry cmd_wait_for_entry = {
.exec = cmd_wait_for_exec .exec = cmd_wait_for_exec
}; };
struct wait_item {
struct cmdq_item *item;
TAILQ_ENTRY(wait_item) entry;
};
struct wait_channel { struct wait_channel {
const char *name; const char *name;
int locked; int locked;
int woken; int woken;
TAILQ_HEAD(, cmd_q) waiters; TAILQ_HEAD(, wait_item) waiters;
TAILQ_HEAD(, cmd_q) lockers; TAILQ_HEAD(, wait_item) lockers;
RB_ENTRY(wait_channel) entry; RB_ENTRY(wait_channel) entry;
}; };
RB_HEAD(wait_channels, wait_channel); RB_HEAD(wait_channels, wait_channel);
struct wait_channels wait_channels = RB_INITIALIZER(wait_channels); static struct wait_channels wait_channels = RB_INITIALIZER(wait_channels);
int wait_channel_cmp(struct wait_channel *, struct wait_channel *); static int wait_channel_cmp(struct wait_channel *, struct wait_channel *);
RB_PROTOTYPE(wait_channels, wait_channel, entry, wait_channel_cmp); RB_GENERATE_STATIC(wait_channels, wait_channel, entry, wait_channel_cmp);
RB_GENERATE(wait_channels, wait_channel, entry, wait_channel_cmp);
int static int
wait_channel_cmp(struct wait_channel *wc1, struct wait_channel *wc2) wait_channel_cmp(struct wait_channel *wc1, struct wait_channel *wc2)
{ {
return (strcmp(wc1->name, wc2->name)); return (strcmp(wc1->name, wc2->name));
} }
enum cmd_retval cmd_wait_for_signal(struct cmd_q *, const char *, static enum cmd_retval cmd_wait_for_signal(struct cmdq_item *, const char *,
struct wait_channel *); struct wait_channel *);
enum cmd_retval cmd_wait_for_wait(struct cmd_q *, const char *, static enum cmd_retval cmd_wait_for_wait(struct cmdq_item *, const char *,
struct wait_channel *); struct wait_channel *);
enum cmd_retval cmd_wait_for_lock(struct cmd_q *, const char *, static enum cmd_retval cmd_wait_for_lock(struct cmdq_item *, const char *,
struct wait_channel *); struct wait_channel *);
enum cmd_retval cmd_wait_for_unlock(struct cmd_q *, const char *, static enum cmd_retval cmd_wait_for_unlock(struct cmdq_item *, const char *,
struct wait_channel *); struct wait_channel *);
struct wait_channel *cmd_wait_for_add(const char *); static struct wait_channel *cmd_wait_for_add(const char *);
void cmd_wait_for_remove(struct wait_channel *wc); static void cmd_wait_for_remove(struct wait_channel *);
struct wait_channel * static struct wait_channel *
cmd_wait_for_add(const char *name) cmd_wait_for_add(const char *name)
{ {
struct wait_channel *wc; struct wait_channel *wc;
@@ -97,7 +101,7 @@ cmd_wait_for_add(const char *name)
return (wc); return (wc);
} }
void static void
cmd_wait_for_remove(struct wait_channel *wc) cmd_wait_for_remove(struct wait_channel *wc)
{ {
if (wc->locked) if (wc->locked)
@@ -113,8 +117,8 @@ cmd_wait_for_remove(struct wait_channel *wc)
free(wc); free(wc);
} }
enum cmd_retval static enum cmd_retval
cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq) cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
const char *name = args->argv[0]; const char *name = args->argv[0];
@@ -124,19 +128,19 @@ cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
wc = RB_FIND(wait_channels, &wait_channels, &wc0); wc = RB_FIND(wait_channels, &wait_channels, &wc0);
if (args_has(args, 'S')) if (args_has(args, 'S'))
return (cmd_wait_for_signal(cmdq, name, wc)); return (cmd_wait_for_signal(item, name, wc));
if (args_has(args, 'L')) if (args_has(args, 'L'))
return (cmd_wait_for_lock(cmdq, name, wc)); return (cmd_wait_for_lock(item, name, wc));
if (args_has(args, 'U')) if (args_has(args, 'U'))
return (cmd_wait_for_unlock(cmdq, name, wc)); return (cmd_wait_for_unlock(item, name, wc));
return (cmd_wait_for_wait(cmdq, name, wc)); return (cmd_wait_for_wait(item, name, wc));
} }
enum cmd_retval static enum cmd_retval
cmd_wait_for_signal(__unused struct cmd_q *cmdq, const char *name, cmd_wait_for_signal(__unused struct cmdq_item *item, const char *name,
struct wait_channel *wc) struct wait_channel *wc)
{ {
struct cmd_q *wq, *wq1; struct wait_item *wi, *wi1;
if (wc == NULL) if (wc == NULL)
wc = cmd_wait_for_add(name); wc = cmd_wait_for_add(name);
@@ -148,24 +152,26 @@ cmd_wait_for_signal(__unused struct cmd_q *cmdq, const char *name,
} }
log_debug("signal wait channel %s, with waiters", wc->name); log_debug("signal wait channel %s, with waiters", wc->name);
TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) { TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
TAILQ_REMOVE(&wc->waiters, wq, waitentry); cmdq_continue(wi->item);
if (!cmdq_free(wq))
cmdq_continue(wq); TAILQ_REMOVE(&wc->waiters, wi, entry);
free(wi);
} }
cmd_wait_for_remove(wc); cmd_wait_for_remove(wc);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
enum cmd_retval static enum cmd_retval
cmd_wait_for_wait(struct cmd_q *cmdq, const char *name, cmd_wait_for_wait(struct cmdq_item *item, const char *name,
struct wait_channel *wc) struct wait_channel *wc)
{ {
struct client *c = cmdq->client; struct client *c = item->client;
struct wait_item *wi;
if (c == NULL || c->session != NULL) { if (c == NULL) {
cmdq_error(cmdq, "not able to wait"); cmdq_error(item, "not able to wait");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -179,18 +185,21 @@ cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
} }
log_debug("wait channel %s not woken (%p)", wc->name, c); log_debug("wait channel %s not woken (%p)", wc->name, c);
TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry); wi = xcalloc(1, sizeof *wi);
cmdq->references++; wi->item = item;
TAILQ_INSERT_TAIL(&wc->waiters, wi, entry);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
enum cmd_retval static enum cmd_retval
cmd_wait_for_lock(struct cmd_q *cmdq, const char *name, cmd_wait_for_lock(struct cmdq_item *item, const char *name,
struct wait_channel *wc) struct wait_channel *wc)
{ {
if (cmdq->client == NULL || cmdq->client->session != NULL) { struct wait_item *wi;
cmdq_error(cmdq, "not able to lock");
if (item->client == NULL) {
cmdq_error(item, "not able to lock");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -198,8 +207,9 @@ cmd_wait_for_lock(struct cmd_q *cmdq, const char *name,
wc = cmd_wait_for_add(name); wc = cmd_wait_for_add(name);
if (wc->locked) { if (wc->locked) {
TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry); wi = xcalloc(1, sizeof *wi);
cmdq->references++; wi->item = item;
TAILQ_INSERT_TAIL(&wc->lockers, wi, entry);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
wc->locked = 1; wc->locked = 1;
@@ -207,21 +217,21 @@ cmd_wait_for_lock(struct cmd_q *cmdq, const char *name,
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
enum cmd_retval static enum cmd_retval
cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name, cmd_wait_for_unlock(struct cmdq_item *item, const char *name,
struct wait_channel *wc) struct wait_channel *wc)
{ {
struct cmd_q *wq; struct wait_item *wi;
if (wc == NULL || !wc->locked) { if (wc == NULL || !wc->locked) {
cmdq_error(cmdq, "channel %s not locked", name); cmdq_error(item, "channel %s not locked", name);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if ((wq = TAILQ_FIRST(&wc->lockers)) != NULL) { if ((wi = TAILQ_FIRST(&wc->lockers)) != NULL) {
TAILQ_REMOVE(&wc->lockers, wq, waitentry); cmdq_continue(wi->item);
if (!cmdq_free(wq)) TAILQ_REMOVE(&wc->lockers, wi, entry);
cmdq_continue(wq); free(wi);
} else { } else {
wc->locked = 0; wc->locked = 0;
cmd_wait_for_remove(wc); cmd_wait_for_remove(wc);
@@ -234,19 +244,19 @@ void
cmd_wait_for_flush(void) cmd_wait_for_flush(void)
{ {
struct wait_channel *wc, *wc1; struct wait_channel *wc, *wc1;
struct cmd_q *wq, *wq1; struct wait_item *wi, *wi1;
RB_FOREACH_SAFE(wc, wait_channels, &wait_channels, wc1) { RB_FOREACH_SAFE(wc, wait_channels, &wait_channels, wc1) {
TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) { TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
TAILQ_REMOVE(&wc->waiters, wq, waitentry); cmdq_continue(wi->item);
if (!cmdq_free(wq)) TAILQ_REMOVE(&wc->waiters, wi, entry);
cmdq_continue(wq); free(wi);
} }
wc->woken = 1; wc->woken = 1;
TAILQ_FOREACH_SAFE(wq, &wc->lockers, waitentry, wq1) { TAILQ_FOREACH_SAFE(wi, &wc->lockers, entry, wi1) {
TAILQ_REMOVE(&wc->lockers, wq, waitentry); cmdq_continue(wi->item);
if (!cmdq_free(wq)) TAILQ_REMOVE(&wc->lockers, wi, entry);
cmdq_continue(wq); free(wi);
} }
wc->locked = 0; wc->locked = 0;
cmd_wait_for_remove(wc); cmd_wait_for_remove(wc);

483
cmd.c
View File

@@ -33,9 +33,7 @@ extern const struct cmd_entry cmd_break_pane_entry;
extern const struct cmd_entry cmd_capture_pane_entry; extern const struct cmd_entry cmd_capture_pane_entry;
extern const struct cmd_entry cmd_choose_buffer_entry; extern const struct cmd_entry cmd_choose_buffer_entry;
extern const struct cmd_entry cmd_choose_client_entry; extern const struct cmd_entry cmd_choose_client_entry;
extern const struct cmd_entry cmd_choose_session_entry;
extern const struct cmd_entry cmd_choose_tree_entry; extern const struct cmd_entry cmd_choose_tree_entry;
extern const struct cmd_entry cmd_choose_window_entry;
extern const struct cmd_entry cmd_clear_history_entry; extern const struct cmd_entry cmd_clear_history_entry;
extern const struct cmd_entry cmd_clock_mode_entry; extern const struct cmd_entry cmd_clock_mode_entry;
extern const struct cmd_entry cmd_command_prompt_entry; extern const struct cmd_entry cmd_command_prompt_entry;
@@ -43,6 +41,7 @@ extern const struct cmd_entry cmd_confirm_before_entry;
extern const struct cmd_entry cmd_copy_mode_entry; extern const struct cmd_entry cmd_copy_mode_entry;
extern const struct cmd_entry cmd_delete_buffer_entry; extern const struct cmd_entry cmd_delete_buffer_entry;
extern const struct cmd_entry cmd_detach_client_entry; extern const struct cmd_entry cmd_detach_client_entry;
extern const struct cmd_entry cmd_display_menu_entry;
extern const struct cmd_entry cmd_display_message_entry; extern const struct cmd_entry cmd_display_message_entry;
extern const struct cmd_entry cmd_display_panes_entry; extern const struct cmd_entry cmd_display_panes_entry;
extern const struct cmd_entry cmd_down_pane_entry; extern const struct cmd_entry cmd_down_pane_entry;
@@ -82,6 +81,7 @@ extern const struct cmd_entry cmd_refresh_client_entry;
extern const struct cmd_entry cmd_rename_session_entry; extern const struct cmd_entry cmd_rename_session_entry;
extern const struct cmd_entry cmd_rename_window_entry; extern const struct cmd_entry cmd_rename_window_entry;
extern const struct cmd_entry cmd_resize_pane_entry; extern const struct cmd_entry cmd_resize_pane_entry;
extern const struct cmd_entry cmd_resize_window_entry;
extern const struct cmd_entry cmd_respawn_pane_entry; extern const struct cmd_entry cmd_respawn_pane_entry;
extern const struct cmd_entry cmd_respawn_window_entry; extern const struct cmd_entry cmd_respawn_window_entry;
extern const struct cmd_entry cmd_rotate_window_entry; extern const struct cmd_entry cmd_rotate_window_entry;
@@ -92,7 +92,6 @@ extern const struct cmd_entry cmd_select_pane_entry;
extern const struct cmd_entry cmd_select_window_entry; extern const struct cmd_entry cmd_select_window_entry;
extern const struct cmd_entry cmd_send_keys_entry; extern const struct cmd_entry cmd_send_keys_entry;
extern const struct cmd_entry cmd_send_prefix_entry; extern const struct cmd_entry cmd_send_prefix_entry;
extern const struct cmd_entry cmd_server_info_entry;
extern const struct cmd_entry cmd_set_buffer_entry; extern const struct cmd_entry cmd_set_buffer_entry;
extern const struct cmd_entry cmd_set_environment_entry; extern const struct cmd_entry cmd_set_environment_entry;
extern const struct cmd_entry cmd_set_hook_entry; extern const struct cmd_entry cmd_set_hook_entry;
@@ -123,9 +122,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_capture_pane_entry, &cmd_capture_pane_entry,
&cmd_choose_buffer_entry, &cmd_choose_buffer_entry,
&cmd_choose_client_entry, &cmd_choose_client_entry,
&cmd_choose_session_entry,
&cmd_choose_tree_entry, &cmd_choose_tree_entry,
&cmd_choose_window_entry,
&cmd_clear_history_entry, &cmd_clear_history_entry,
&cmd_clock_mode_entry, &cmd_clock_mode_entry,
&cmd_command_prompt_entry, &cmd_command_prompt_entry,
@@ -133,6 +130,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_copy_mode_entry, &cmd_copy_mode_entry,
&cmd_delete_buffer_entry, &cmd_delete_buffer_entry,
&cmd_detach_client_entry, &cmd_detach_client_entry,
&cmd_display_menu_entry,
&cmd_display_message_entry, &cmd_display_message_entry,
&cmd_display_panes_entry, &cmd_display_panes_entry,
&cmd_find_window_entry, &cmd_find_window_entry,
@@ -171,6 +169,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_rename_session_entry, &cmd_rename_session_entry,
&cmd_rename_window_entry, &cmd_rename_window_entry,
&cmd_resize_pane_entry, &cmd_resize_pane_entry,
&cmd_resize_window_entry,
&cmd_respawn_pane_entry, &cmd_respawn_pane_entry,
&cmd_respawn_window_entry, &cmd_respawn_window_entry,
&cmd_rotate_window_entry, &cmd_rotate_window_entry,
@@ -181,7 +180,6 @@ const struct cmd_entry *cmd_table[] = {
&cmd_select_window_entry, &cmd_select_window_entry,
&cmd_send_keys_entry, &cmd_send_keys_entry,
&cmd_send_prefix_entry, &cmd_send_prefix_entry,
&cmd_server_info_entry,
&cmd_set_buffer_entry, &cmd_set_buffer_entry,
&cmd_set_environment_entry, &cmd_set_environment_entry,
&cmd_set_hook_entry, &cmd_set_hook_entry,
@@ -206,6 +204,47 @@ const struct cmd_entry *cmd_table[] = {
NULL NULL
}; };
static u_int cmd_list_next_group = 1;
void printflike(3, 4)
cmd_log_argv(int argc, char **argv, const char *fmt, ...)
{
char *prefix;
va_list ap;
int i;
va_start(ap, fmt);
xvasprintf(&prefix, fmt, ap);
va_end(ap);
for (i = 0; i < argc; i++)
log_debug("%s: argv[%d]=%s", prefix, i, argv[i]);
free(prefix);
}
void
cmd_prepend_argv(int *argc, char ***argv, char *arg)
{
char **new_argv;
int i;
new_argv = xreallocarray(NULL, (*argc) + 1, sizeof *new_argv);
new_argv[0] = xstrdup(arg);
for (i = 0; i < *argc; i++)
new_argv[1 + i] = (*argv)[i];
free(*argv);
*argv = new_argv;
(*argc)++;
}
void
cmd_append_argv(int *argc, char ***argv, char *arg)
{
*argv = xreallocarray(*argv, (*argc) + 1, sizeof **argv);
(*argv)[(*argc)++] = xstrdup(arg);
}
int int
cmd_pack_argv(int argc, char **argv, char *buf, size_t len) cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
{ {
@@ -214,6 +253,7 @@ cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
if (argc == 0) if (argc == 0)
return (0); return (0);
cmd_log_argv(argc, argv, "%s", __func__);
*buf = '\0'; *buf = '\0';
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
@@ -246,9 +286,11 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
arglen = strlen(buf) + 1; arglen = strlen(buf) + 1;
(*argv)[i] = xstrdup(buf); (*argv)[i] = xstrdup(buf);
buf += arglen; buf += arglen;
len -= arglen; len -= arglen;
} }
cmd_log_argv(argc, *argv, "%s", __func__);
return (0); return (0);
} }
@@ -307,46 +349,103 @@ cmd_stringify_argv(int argc, char **argv)
return (buf); return (buf);
} }
struct cmd * char *
cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause) cmd_get_alias(const char *name)
{ {
const struct cmd_entry **entryp, *entry; struct options_entry *o;
struct cmd *cmd; struct options_array_item *a;
struct args *args; union options_value *ov;
char s[BUFSIZ]; size_t wanted, n;
int ambiguous = 0; const char *equals;
*cause = NULL; o = options_get_only(global_options, "command-alias");
if (argc == 0) { if (o == NULL)
xasprintf(cause, "no command");
return (NULL); return (NULL);
} wanted = strlen(name);
entry = NULL; a = options_array_first(o);
for (entryp = cmd_table; *entryp != NULL; entryp++) { while (a != NULL) {
if ((*entryp)->alias != NULL && ov = options_array_item_value(a);
strcmp((*entryp)->alias, argv[0]) == 0) {
equals = strchr(ov->string, '=');
if (equals != NULL) {
n = equals - ov->string;
if (n == wanted && strncmp(name, ov->string, n) == 0)
return (xstrdup(equals + 1));
}
a = options_array_next(a);
}
return (NULL);
}
static const struct cmd_entry *
cmd_find(const char *name, char **cause)
{
const struct cmd_entry **loop, *entry, *found = NULL;
int ambiguous;
char s[8192];
ambiguous = 0;
for (loop = cmd_table; *loop != NULL; loop++) {
entry = *loop;
if (entry->alias != NULL && strcmp(entry->alias, name) == 0) {
ambiguous = 0; ambiguous = 0;
entry = *entryp; found = entry;
break; break;
} }
if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0) if (strncmp(entry->name, name, strlen(name)) != 0)
continue; continue;
if (entry != NULL) if (found != NULL)
ambiguous = 1; ambiguous = 1;
entry = *entryp; found = entry;
/* Bail now if an exact match. */ if (strcmp(entry->name, name) == 0)
if (strcmp(entry->name, argv[0]) == 0)
break; break;
} }
if (ambiguous) if (ambiguous)
goto ambiguous; goto ambiguous;
if (entry == NULL) { if (found == NULL) {
xasprintf(cause, "unknown command: %s", argv[0]); xasprintf(cause, "unknown command: %s", name);
return (NULL); return (NULL);
} }
return (found);
ambiguous:
*s = '\0';
for (loop = cmd_table; *loop != NULL; loop++) {
entry = *loop;
if (strncmp(entry->name, name, strlen(name)) != 0)
continue;
if (strlcat(s, entry->name, sizeof s) >= sizeof s)
break;
if (strlcat(s, ", ", sizeof s) >= sizeof s)
break;
}
s[strlen(s) - 2] = '\0';
xasprintf(cause, "ambiguous command: %s, could be: %s", name, s);
return (NULL);
}
struct cmd *
cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
{
const struct cmd_entry *entry;
const char *name;
struct cmd *cmd;
struct args *args;
if (argc == 0) {
xasprintf(cause, "no command");
return (NULL);
}
name = argv[0];
entry = cmd_find(name, cause);
if (entry == NULL)
return (NULL);
cmd_log_argv(argc, argv, "%s: %s", __func__, entry->name);
args = args_parse(entry->args.template, argc, argv); args = args_parse(entry->args.template, argc, argv);
if (args == NULL) if (args == NULL)
@@ -364,21 +463,11 @@ cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
cmd->file = xstrdup(file); cmd->file = xstrdup(file);
cmd->line = line; cmd->line = line;
return (cmd); cmd->alias = NULL;
cmd->argc = argc;
cmd->argv = cmd_copy_argv(argc, argv);
ambiguous: return (cmd);
*s = '\0';
for (entryp = cmd_table; *entryp != NULL; entryp++) {
if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0)
continue;
if (strlcat(s, (*entryp)->name, sizeof s) >= sizeof s)
break;
if (strlcat(s, ", ", sizeof s) >= sizeof s)
break;
}
s[strlen(s) - 2] = '\0';
xasprintf(cause, "ambiguous command: %s, could be: %s", argv[0], s);
return (NULL);
usage: usage:
if (args != NULL) if (args != NULL)
@@ -387,177 +476,16 @@ usage:
return (NULL); return (NULL);
} }
static int void
cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag, cmd_free(struct cmd *cmd)
struct cmd_q *cmdq, struct cmd_q *parent)
{ {
int targetflags, error; free(cmd->alias);
struct cmd_find_state *fs = NULL; cmd_free_argv(cmd->argc, cmd->argv);
struct cmd_find_state *current = NULL;
struct cmd_find_state tmp;
if (flag == CMD_NONE || free(cmd->file);
flag == CMD_CLIENT ||
flag == CMD_CLIENT_CANFAIL)
return (0);
if (c == 't') args_free(cmd->args);
fs = &cmdq->state.tflag; free(cmd);
else if (c == 's')
fs = &cmdq->state.sflag;
if (flag == CMD_SESSION_WITHPANE) {
if (target != NULL && target[strcspn(target, ":.")] != '\0')
flag = CMD_PANE;
else
flag = CMD_SESSION;
}
targetflags = 0;
switch (flag) {
case CMD_SESSION:
case CMD_SESSION_CANFAIL:
case CMD_SESSION_PREFERUNATTACHED:
if (flag == CMD_SESSION_CANFAIL)
targetflags |= CMD_FIND_QUIET;
if (flag == CMD_SESSION_PREFERUNATTACHED)
targetflags |= CMD_FIND_PREFER_UNATTACHED;
break;
case CMD_MOVEW_R:
flag = CMD_WINDOW_INDEX;
/* FALLTHROUGH */
case CMD_WINDOW:
case CMD_WINDOW_CANFAIL:
case CMD_WINDOW_MARKED:
case CMD_WINDOW_INDEX:
if (flag == CMD_WINDOW_CANFAIL)
targetflags |= CMD_FIND_QUIET;
if (flag == CMD_WINDOW_MARKED)
targetflags |= CMD_FIND_DEFAULT_MARKED;
if (flag == CMD_WINDOW_INDEX)
targetflags |= CMD_FIND_WINDOW_INDEX;
break;
case CMD_PANE:
case CMD_PANE_CANFAIL:
case CMD_PANE_MARKED:
if (flag == CMD_PANE_CANFAIL)
targetflags |= CMD_FIND_QUIET;
if (flag == CMD_PANE_MARKED)
targetflags |= CMD_FIND_DEFAULT_MARKED;
break;
default:
fatalx("unknown %cflag %d", c, flag);
}
log_debug("%s: flag %c %d %#x", __func__, c, flag, targetflags);
if (parent != NULL) {
if (c == 't')
current = &parent->state.tflag;
else if (c == 's')
current = &parent->state.sflag;
} else {
error = cmd_find_current(&tmp, cmdq, targetflags);
if (error != 0 && ~targetflags & CMD_FIND_QUIET)
return (-1);
current = &tmp;
}
switch (flag) {
case CMD_NONE:
case CMD_CLIENT:
case CMD_CLIENT_CANFAIL:
return (0);
case CMD_SESSION:
case CMD_SESSION_CANFAIL:
case CMD_SESSION_PREFERUNATTACHED:
case CMD_SESSION_WITHPANE:
error = cmd_find_target(fs, current, cmdq, target,
CMD_FIND_SESSION, targetflags);
if (error != 0 && ~targetflags & CMD_FIND_QUIET)
return (-1);
break;
case CMD_MOVEW_R:
error = cmd_find_target(fs, current, cmdq, target,
CMD_FIND_SESSION, CMD_FIND_QUIET);
if (error == 0)
break;
/* FALLTHROUGH */
case CMD_WINDOW:
case CMD_WINDOW_CANFAIL:
case CMD_WINDOW_MARKED:
case CMD_WINDOW_INDEX:
error = cmd_find_target(fs, current, cmdq, target,
CMD_FIND_WINDOW, targetflags);
if (error != 0 && ~targetflags & CMD_FIND_QUIET)
return (-1);
break;
case CMD_PANE:
case CMD_PANE_CANFAIL:
case CMD_PANE_MARKED:
error = cmd_find_target(fs, current, cmdq, target,
CMD_FIND_PANE, targetflags);
if (error != 0 && ~targetflags & CMD_FIND_QUIET)
return (-1);
break;
default:
fatalx("unknown %cflag %d", c, flag);
}
return (0);
}
int
cmd_prepare_state(struct cmd *cmd, struct cmd_q *cmdq, struct cmd_q *parent)
{
const struct cmd_entry *entry = cmd->entry;
struct cmd_state *state = &cmdq->state;
char *tmp;
enum cmd_entry_flag flag;
const char *s;
int error;
tmp = cmd_print(cmd);
log_debug("preparing state for %s (client %p)", tmp, cmdq->client);
free(tmp);
state->c = NULL;
cmd_find_clear_state(&state->tflag, NULL, 0);
cmd_find_clear_state(&state->sflag, NULL, 0);
flag = cmd->entry->cflag;
if (flag == CMD_NONE) {
flag = cmd->entry->tflag;
if (flag == CMD_CLIENT || flag == CMD_CLIENT_CANFAIL)
s = args_get(cmd->args, 't');
else
s = NULL;
} else
s = args_get(cmd->args, 'c');
switch (flag) {
case CMD_CLIENT:
state->c = cmd_find_client(cmdq, s, 0);
if (state->c == NULL)
return (-1);
break;
default:
state->c = cmd_find_client(cmdq, s, 1);
break;
}
s = args_get(cmd->args, 't');
log_debug("preparing -t state: target %s", s == NULL ? "none" : s);
error = cmd_prepare_state_flag('t', s, entry->tflag, cmdq, parent);
if (error != 0)
return (error);
s = args_get(cmd->args, 's');
log_debug("preparing -s state: target %s", s == NULL ? "none" : s);
error = cmd_prepare_state_flag('s', s, entry->sflag, cmdq, parent);
if (error != 0)
return (error);
return (0);
} }
char * char *
@@ -575,6 +503,83 @@ cmd_print(struct cmd *cmd)
return (out); return (out);
} }
struct cmd_list *
cmd_list_new(void)
{
struct cmd_list *cmdlist;
cmdlist = xcalloc(1, sizeof *cmdlist);
cmdlist->references = 1;
cmdlist->group = cmd_list_next_group++;
TAILQ_INIT(&cmdlist->list);
return (cmdlist);
}
void
cmd_list_append(struct cmd_list *cmdlist, struct cmd *cmd)
{
cmd->group = cmdlist->group;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
}
void
cmd_list_move(struct cmd_list *cmdlist, struct cmd_list *from)
{
struct cmd *cmd, *cmd1;
TAILQ_FOREACH_SAFE(cmd, &from->list, qentry, cmd1) {
TAILQ_REMOVE(&from->list, cmd, qentry);
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
}
cmdlist->group = cmd_list_next_group++;
}
void
cmd_list_free(struct cmd_list *cmdlist)
{
struct cmd *cmd, *cmd1;
if (--cmdlist->references != 0)
return;
TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) {
TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
cmd_free(cmd);
}
free(cmdlist);
}
char *
cmd_list_print(struct cmd_list *cmdlist, int escaped)
{
struct cmd *cmd;
char *buf, *this;
size_t len;
len = 1;
buf = xcalloc(1, len);
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
this = cmd_print(cmd);
len += strlen(this) + 4;
buf = xrealloc(buf, len);
strlcat(buf, this, len);
if (TAILQ_NEXT(cmd, qentry) != NULL) {
if (escaped)
strlcat(buf, " \\; ", len);
else
strlcat(buf, " ; ", len);
}
free(this);
}
return (buf);
}
/* Adjust current mouse position for a pane. */ /* Adjust current mouse position for a pane. */
int int
cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp, cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
@@ -583,25 +588,26 @@ cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
u_int x, y; u_int x, y;
if (last) { if (last) {
x = m->lx; x = m->lx + m->ox;
y = m->ly; y = m->ly + m->oy;
} else { } else {
x = m->x; x = m->x + m->ox;
y = m->y; y = m->y + m->oy;
} }
log_debug("%s: x=%u, y=%u%s", __func__, x, y, last ? " (last)" : "");
if (m->statusat == 0 && y > 0) if (m->statusat == 0 && y >= m->statuslines)
y--; y -= m->statuslines;
else if (m->statusat > 0 && y >= (u_int)m->statusat)
y = m->statusat - 1;
if (x < wp->xoff || x >= wp->xoff + wp->sx) if (x < wp->xoff || x >= wp->xoff + wp->sx)
return (-1); return (-1);
if (y < wp->yoff || y >= wp->yoff + wp->sy) if (y < wp->yoff || y >= wp->yoff + wp->sy)
return (-1); return (-1);
*xp = x - wp->xoff; if (xp != NULL)
*yp = y - wp->yoff; *xp = x - wp->xoff;
if (yp != NULL)
*yp = y - wp->yoff;
return (0); return (0);
} }
@@ -611,17 +617,22 @@ cmd_mouse_window(struct mouse_event *m, struct session **sp)
{ {
struct session *s; struct session *s;
struct window *w; struct window *w;
struct winlink *wl;
if (!m->valid || m->s == -1 || m->w == -1) if (!m->valid)
return (NULL); return (NULL);
if ((s = session_find_by_id(m->s)) == NULL) if (m->s == -1 || (s = session_find_by_id(m->s)) == NULL)
return (NULL); return (NULL);
if ((w = window_find_by_id(m->w)) == NULL) if (m->w == -1)
return (NULL); wl = s->curw;
else {
if ((w = window_find_by_id(m->w)) == NULL)
return (NULL);
wl = winlink_find_by_window(&s->windows, w);
}
if (sp != NULL) if (sp != NULL)
*sp = s; *sp = s;
return (winlink_find_by_window(&s->windows, w)); return (wl);
} }
/* Get current mouse pane if any. */ /* Get current mouse pane if any. */
@@ -649,8 +660,8 @@ char *
cmd_template_replace(const char *template, const char *s, int idx) cmd_template_replace(const char *template, const char *s, int idx)
{ {
char ch, *buf; char ch, *buf;
const char *ptr; const char *ptr, *cp, quote[] = "\"\\$;";
int replaced; int replaced, quoted;
size_t len; size_t len;
if (strchr(template, '%') == NULL) if (strchr(template, '%') == NULL)
@@ -672,9 +683,17 @@ cmd_template_replace(const char *template, const char *s, int idx)
} }
ptr++; ptr++;
len += strlen(s); quoted = (*ptr == '%');
buf = xrealloc(buf, len + 1); if (quoted)
strlcat(buf, s, len + 1); ptr++;
buf = xrealloc(buf, len + (strlen(s) * 3) + 1);
for (cp = s; *cp != '\0'; cp++) {
if (quoted && strchr(quote, *cp) != NULL)
buf[len++] = '\\';
buf[len++] = *cp;
}
buf[len] = '\0';
continue; continue;
} }
buf = xrealloc(buf, len + 2); buf = xrealloc(buf, len + 2);

View File

@@ -48,7 +48,7 @@ colour_to_6cube(int v)
* map our RGB colour to the closest in the cube, also work out the closest * map our RGB colour to the closest in the cube, also work out the closest
* grey, and use the nearest of the two. * grey, and use the nearest of the two.
* *
* Note that the xterm has much lower resolution for darker colors (they are * Note that the xterm has much lower resolution for darker colours (they are
* not evenly spread out), so our 6 levels are not evenly spread: 0x0, 0x5f * not evenly spread out), so our 6 levels are not evenly spread: 0x0, 0x5f
* (95), 0x87 (135), 0xaf (175), 0xd7 (215) and 0xff (255). Greys are more * (95), 0x87 (135), 0xaf (175), 0xd7 (215) and 0xff (255). Greys are more
* evenly spread (8, 18, 28 ... 238). * evenly spread (8, 18, 28 ... 238).
@@ -141,6 +141,8 @@ colour_tostring(int c)
return ("white"); return ("white");
case 8: case 8:
return ("default"); return ("default");
case 9:
return ("terminal");
case 90: case 90:
return ("brightblack"); return ("brightblack");
case 91: case 91:
@@ -158,7 +160,7 @@ colour_tostring(int c)
case 97: case 97:
return ("brightwhite"); return ("brightwhite");
} }
return (NULL); return ("invalid");
} }
/* Convert colour from string. */ /* Convert colour from string. */
@@ -188,6 +190,11 @@ colour_fromstring(const char *s)
return (n | COLOUR_FLAG_256); return (n | COLOUR_FLAG_256);
} }
if (strcasecmp(s, "default") == 0)
return (8);
if (strcasecmp(s, "terminal") == 0)
return (9);
if (strcasecmp(s, "black") == 0 || strcmp(s, "0") == 0) if (strcasecmp(s, "black") == 0 || strcmp(s, "0") == 0)
return (0); return (0);
if (strcasecmp(s, "red") == 0 || strcmp(s, "1") == 0) if (strcasecmp(s, "red") == 0 || strcmp(s, "1") == 0)
@@ -204,8 +211,6 @@ colour_fromstring(const char *s)
return (6); return (6);
if (strcasecmp(s, "white") == 0 || strcmp(s, "7") == 0) if (strcasecmp(s, "white") == 0 || strcmp(s, "7") == 0)
return (7); return (7);
if (strcasecmp(s, "default") == 0 || strcmp(s, "8") == 0)
return (8);
if (strcasecmp(s, "brightblack") == 0 || strcmp(s, "90") == 0) if (strcasecmp(s, "brightblack") == 0 || strcmp(s, "90") == 0)
return (90); return (90);
if (strcasecmp(s, "brightred") == 0 || strcmp(s, "91") == 0) if (strcasecmp(s, "brightred") == 0 || strcmp(s, "91") == 0)
@@ -225,11 +230,85 @@ colour_fromstring(const char *s)
return (-1); return (-1);
} }
/* Convert 256 colour palette to 16. */ /* Convert 256 colour to RGB colour. */
u_char int
colour_256to16(u_char c) colour_256toRGB(int c)
{ {
static const u_char table[256] = { static const int table[256] = {
0x000000, 0x800000, 0x008000, 0x808000,
0x000080, 0x800080, 0x008080, 0xc0c0c0,
0x808080, 0xff0000, 0x00ff00, 0xffff00,
0x0000ff, 0xff00ff, 0x00ffff, 0xffffff,
0x000000, 0x00005f, 0x000087, 0x0000af,
0x0000d7, 0x0000ff, 0x005f00, 0x005f5f,
0x005f87, 0x005faf, 0x005fd7, 0x005fff,
0x008700, 0x00875f, 0x008787, 0x0087af,
0x0087d7, 0x0087ff, 0x00af00, 0x00af5f,
0x00af87, 0x00afaf, 0x00afd7, 0x00afff,
0x00d700, 0x00d75f, 0x00d787, 0x00d7af,
0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f,
0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff,
0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af,
0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f,
0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff,
0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af,
0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f,
0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff,
0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af,
0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f,
0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff,
0x870000, 0x87005f, 0x870087, 0x8700af,
0x8700d7, 0x8700ff, 0x875f00, 0x875f5f,
0x875f87, 0x875faf, 0x875fd7, 0x875fff,
0x878700, 0x87875f, 0x878787, 0x8787af,
0x8787d7, 0x8787ff, 0x87af00, 0x87af5f,
0x87af87, 0x87afaf, 0x87afd7, 0x87afff,
0x87d700, 0x87d75f, 0x87d787, 0x87d7af,
0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f,
0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff,
0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af,
0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f,
0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff,
0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af,
0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f,
0xafaf87, 0xafafaf, 0xafafd7, 0xafafff,
0xafd700, 0xafd75f, 0xafd787, 0xafd7af,
0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f,
0xafff87, 0xafffaf, 0xafffd7, 0xafffff,
0xd70000, 0xd7005f, 0xd70087, 0xd700af,
0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f,
0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff,
0xd78700, 0xd7875f, 0xd78787, 0xd787af,
0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f,
0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff,
0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af,
0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f,
0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff,
0xff0000, 0xff005f, 0xff0087, 0xff00af,
0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f,
0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff,
0xff8700, 0xff875f, 0xff8787, 0xff87af,
0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f,
0xffaf87, 0xffafaf, 0xffafd7, 0xffafff,
0xffd700, 0xffd75f, 0xffd787, 0xffd7af,
0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f,
0xffff87, 0xffffaf, 0xffffd7, 0xffffff,
0x080808, 0x121212, 0x1c1c1c, 0x262626,
0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e,
0x585858, 0x626262, 0x6c6c6c, 0x767676,
0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e,
0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6,
0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee
};
return (table[c & 0xff] | COLOUR_FLAG_RGB);
}
/* Convert 256 colour to 16 colour. */
int
colour_256to16(int c)
{
static const char table[256] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 4, 4, 4, 12, 12, 2, 6, 4, 4, 12, 12, 2, 2, 6, 4, 0, 4, 4, 4, 12, 12, 2, 6, 4, 4, 12, 12, 2, 2, 6, 4,
12, 12, 2, 2, 2, 6, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10, 12, 12, 2, 2, 2, 6, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10,
@@ -248,5 +327,5 @@ colour_256to16(u_char c)
8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15
}; };
return (table[c]); return (table[c & 0xff]);
} }

101
compat.h
View File

@@ -17,6 +17,15 @@
#ifndef COMPAT_H #ifndef COMPAT_H
#define COMPAT_H #define COMPAT_H
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <limits.h>
#include <stdio.h>
#include <termios.h>
#include <wchar.h>
#ifndef __GNUC__ #ifndef __GNUC__
#define __attribute__(a) #define __attribute__(a)
#endif #endif
@@ -43,11 +52,13 @@
#include <sys/filio.h> #include <sys/filio.h>
#endif #endif
#ifndef HAVE_BSD_TYPES #ifdef HAVE_ERR_H
typedef uint8_t u_int8_t; #include <err.h>
typedef uint16_t u_int16_t; #else
typedef uint32_t u_int32_t; void err(int, const char *, ...);
typedef uint64_t u_int64_t; void errx(int, const char *, ...);
void warn(const char *, ...);
void warnx(const char *, ...);
#endif #endif
#ifndef HAVE_PATHS_H #ifndef HAVE_PATHS_H
@@ -56,6 +67,17 @@ typedef uint64_t u_int64_t;
#define _PATH_DEVNULL "/dev/null" #define _PATH_DEVNULL "/dev/null"
#define _PATH_TTY "/dev/tty" #define _PATH_TTY "/dev/tty"
#define _PATH_DEV "/dev/" #define _PATH_DEV "/dev/"
#define _PATH_DEFPATH "/usr/bin:/bin"
#endif
#ifndef __OpenBSD__
#define pledge(s, p) (0)
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#else
#include <inttypes.h>
#endif #endif
#ifdef HAVE_QUEUE_H #ifdef HAVE_QUEUE_H
@@ -80,17 +102,17 @@ typedef uint64_t u_int64_t;
#include <paths.h> #include <paths.h>
#endif #endif
#ifdef HAVE_FORKPTY
#ifdef HAVE_LIBUTIL_H #ifdef HAVE_LIBUTIL_H
#include <libutil.h> #include <libutil.h>
#endif #endif
#ifdef HAVE_PTY_H #ifdef HAVE_PTY_H
#include <pty.h> #include <pty.h>
#endif #endif
#ifdef HAVE_UTIL_H #ifdef HAVE_UTIL_H
#include <util.h> #include <util.h>
#endif #endif
#endif
#ifdef HAVE_VIS #ifdef HAVE_VIS
#include <vis.h> #include <vis.h>
@@ -104,12 +126,6 @@ typedef uint64_t u_int64_t;
#include "compat/imsg.h" #include "compat/imsg.h"
#endif #endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#else
#include <inttypes.h>
#endif
#ifdef BROKEN_CMSG_FIRSTHDR #ifdef BROKEN_CMSG_FIRSTHDR
#undef CMSG_FIRSTHDR #undef CMSG_FIRSTHDR
#define CMSG_FIRSTHDR(mhdr) \ #define CMSG_FIRSTHDR(mhdr) \
@@ -196,6 +212,16 @@ typedef uint64_t u_int64_t;
#define flock(fd, op) (0) #define flock(fd, op) (0)
#endif #endif
#ifndef HAVE_EXPLICIT_BZERO
/* explicit_bzero.c */
void explicit_bzero(void *, size_t);
#endif
#ifndef HAVE_GETDTABLECOUNT
/* getdtablecount.c */
int getdtablecount(void);
#endif
#ifndef HAVE_CLOSEFROM #ifndef HAVE_CLOSEFROM
/* closefrom.c */ /* closefrom.c */
void closefrom(int); void closefrom(int);
@@ -226,6 +252,21 @@ size_t strlcpy(char *, const char *, size_t);
size_t strlcat(char *, const char *, size_t); size_t strlcat(char *, const char *, size_t);
#endif #endif
#ifndef HAVE_STRNLEN
/* strnlen.c */
size_t strnlen(const char *, size_t);
#endif
#ifndef HAVE_STRNDUP
/* strndup.c */
char *strndup(const char *, size_t);
#endif
#ifndef HAVE_MEMMEM
/* memmem.c */
void *memmem(const void *, size_t, const void *, size_t);
#endif
#ifndef HAVE_DAEMON #ifndef HAVE_DAEMON
/* daemon.c */ /* daemon.c */
int daemon(int, int); int daemon(int, int);
@@ -242,14 +283,22 @@ void setproctitle(const char *, ...);
#endif #endif
#ifndef HAVE_B64_NTOP #ifndef HAVE_B64_NTOP
/* b64_ntop.c */ /* base64.c */
#undef b64_ntop /* for Cygwin */ #undef b64_ntop
#undef b64_pton
int b64_ntop(const char *, size_t, char *, size_t); int b64_ntop(const char *, size_t, char *, size_t);
int b64_pton(const char *, u_char *, size_t);
#endif
#ifndef HAVE_FDFORKPTY
/* fdforkpty.c */
int getptmfd(void);
pid_t fdforkpty(int, int *, char *, struct termios *,
struct winsize *);
#endif #endif
#ifndef HAVE_FORKPTY #ifndef HAVE_FORKPTY
/* forkpty.c */ /* forkpty.c */
#include <sys/ioctl.h>
pid_t forkpty(int *, char *, struct termios *, struct winsize *); pid_t forkpty(int *, char *, struct termios *, struct winsize *);
#endif #endif
@@ -264,10 +313,6 @@ int vasprintf(char **, const char *, va_list);
char *fgetln(FILE *, size_t *); char *fgetln(FILE *, size_t *);
#endif #endif
#ifndef HAVE_FPARSELN
char *fparseln(FILE *, size_t *, size_t *, const char *, int);
#endif
#ifndef HAVE_SETENV #ifndef HAVE_SETENV
/* setenv.c */ /* setenv.c */
int setenv(const char *, const char *, int); int setenv(const char *, const char *, int);
@@ -279,10 +324,9 @@ int unsetenv(const char *);
void cfmakeraw(struct termios *); void cfmakeraw(struct termios *);
#endif #endif
#ifndef HAVE_OPENAT #ifndef HAVE_FREEZERO
/* openat.c */ /* freezero.c */
#define AT_FDCWD -100 void freezero(void *, size_t);
int openat(int, const char *, int, ...);
#endif #endif
#ifndef HAVE_REALLOCARRAY #ifndef HAVE_REALLOCARRAY
@@ -290,6 +334,11 @@ int openat(int, const char *, int, ...);
void *reallocarray(void *, size_t, size_t); void *reallocarray(void *, size_t, size_t);
#endif #endif
#ifndef HAVE_RECALLOCARRAY
/* recallocarray.c */
void *recallocarray(void *, size_t, size_t, size_t);
#endif
#ifdef HAVE_UTF8PROC #ifdef HAVE_UTF8PROC
/* utf8proc.c */ /* utf8proc.c */
int utf8proc_wcwidth(wchar_t); int utf8proc_wcwidth(wchar_t);
@@ -297,9 +346,7 @@ int utf8proc_mbtowc(wchar_t *, const char *, size_t);
int utf8proc_wctomb(char *, wchar_t); int utf8proc_wctomb(char *, wchar_t);
#endif #endif
#ifdef HAVE_GETOPT #ifndef HAVE_GETOPT
#include <getopt.h>
#else
/* getopt.c */ /* getopt.c */
extern int BSDopterr; extern int BSDopterr;
extern int BSDoptind; extern int BSDoptind;

View File

@@ -14,16 +14,15 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <sys/types.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#else
#include <inttypes.h>
#endif
#include <string.h> #include <string.h>
#include <stdlib.h>
#include "tmux.h" #include "compat.h"
#include "xmalloc.h"
int int
asprintf(char **ret, const char *fmt, ...) asprintf(char **ret, const char *fmt, ...)

View File

@@ -1,5 +1,7 @@
/* $OpenBSD: base64.c,v 1.8 2015/01/16 16:48:51 deraadt Exp $ */
/* /*
* Copyright (c) 1996, 1998 by Internet Software Consortium. * Copyright (c) 1996 by Internet Software Consortium.
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -41,19 +43,18 @@
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <arpa/nameser.h>
#include <ctype.h> #include <ctype.h>
#include <resolv.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define Assert(Cond) if (!(Cond)) abort()
static const char Base64[] = static const char Base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char Pad64 = '='; static const char Pad64 = '=';
@@ -122,11 +123,16 @@ static const char Pad64 = '=';
*/ */
int int
b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) { b64_ntop(src, srclength, target, targsize)
u_char const *src;
size_t srclength;
char *target;
size_t targsize;
{
size_t datalength = 0; size_t datalength = 0;
uint8_t input[3]; u_char input[3];
uint8_t output[4]; u_char output[4];
size_t i; int i;
while (2 < srclength) { while (2 < srclength) {
input[0] = *src++; input[0] = *src++;
@@ -138,10 +144,6 @@ b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) {
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
output[3] = input[2] & 0x3f; output[3] = input[2] & 0x3f;
Assert(output[0] < 64);
Assert(output[1] < 64);
Assert(output[2] < 64);
Assert(output[3] < 64);
if (datalength + 4 > targsize) if (datalength + 4 > targsize)
return (-1); return (-1);
@@ -161,9 +163,6 @@ b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) {
output[0] = input[0] >> 2; output[0] = input[0] >> 2;
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
Assert(output[0] < 64);
Assert(output[1] < 64);
Assert(output[2] < 64);
if (datalength + 4 > targsize) if (datalength + 4 > targsize)
return (-1); return (-1);
@@ -180,3 +179,137 @@ b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) {
target[datalength] = '\0'; /* Returned value doesn't count \0. */ target[datalength] = '\0'; /* Returned value doesn't count \0. */
return (datalength); return (datalength);
} }
/* skips all whitespace anywhere.
converts characters, four at a time, starting at (or after)
src from base - 64 numbers into three 8 bit bytes in the target area.
it returns the number of data bytes stored at the target, or -1 on error.
*/
int
b64_pton(src, target, targsize)
char const *src;
u_char *target;
size_t targsize;
{
int tarindex, state, ch;
u_char nextbyte;
char *pos;
state = 0;
tarindex = 0;
while ((ch = (unsigned char)*src++) != '\0') {
if (isspace(ch)) /* Skip whitespace anywhere. */
continue;
if (ch == Pad64)
break;
pos = strchr(Base64, ch);
if (pos == 0) /* A non-base64 character. */
return (-1);
switch (state) {
case 0:
if (target) {
if (tarindex >= targsize)
return (-1);
target[tarindex] = (pos - Base64) << 2;
}
state = 1;
break;
case 1:
if (target) {
if (tarindex >= targsize)
return (-1);
target[tarindex] |= (pos - Base64) >> 4;
nextbyte = ((pos - Base64) & 0x0f) << 4;
if (tarindex + 1 < targsize)
target[tarindex+1] = nextbyte;
else if (nextbyte)
return (-1);
}
tarindex++;
state = 2;
break;
case 2:
if (target) {
if (tarindex >= targsize)
return (-1);
target[tarindex] |= (pos - Base64) >> 2;
nextbyte = ((pos - Base64) & 0x03) << 6;
if (tarindex + 1 < targsize)
target[tarindex+1] = nextbyte;
else if (nextbyte)
return (-1);
}
tarindex++;
state = 3;
break;
case 3:
if (target) {
if (tarindex >= targsize)
return (-1);
target[tarindex] |= (pos - Base64);
}
tarindex++;
state = 0;
break;
}
}
/*
* We are done decoding Base-64 chars. Let's see if we ended
* on a byte boundary, and/or with erroneous trailing characters.
*/
if (ch == Pad64) { /* We got a pad char. */
ch = (unsigned char)*src++; /* Skip it, get next. */
switch (state) {
case 0: /* Invalid = in first position */
case 1: /* Invalid = in second position */
return (-1);
case 2: /* Valid, means one byte of info */
/* Skip any number of spaces. */
for (; ch != '\0'; ch = (unsigned char)*src++)
if (!isspace(ch))
break;
/* Make sure there is another trailing = sign. */
if (ch != Pad64)
return (-1);
ch = (unsigned char)*src++; /* Skip the = */
/* Fall through to "single trailing =" case. */
/* FALLTHROUGH */
case 3: /* Valid, means two bytes of info */
/*
* We know this char is an =. Is there anything but
* whitespace after it?
*/
for (; ch != '\0'; ch = (unsigned char)*src++)
if (!isspace(ch))
return (-1);
/*
* Now make sure for cases 2 and 3 that the "extra"
* bits that slopped past the last full byte were
* zeros. If we don't check them, they become a
* subliminal channel.
*/
if (target && tarindex < targsize &&
target[tarindex] != 0)
return (-1);
}
} else {
/*
* We ended by seeing the end of the string. Make sure we
* have no partial bytes lying around.
*/
if (state != 0)
return (-1);
}
return (tarindex);
}

View File

@@ -15,9 +15,12 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <string.h> #include <sys/types.h>
#include "tmux.h" #include <string.h>
#include <termios.h>
#include "compat.h"
void void
cfmakeraw(struct termios *tio) cfmakeraw(struct termios *tio)

View File

@@ -45,7 +45,7 @@
# endif # endif
#endif #endif
#include "tmux.h" #include "compat.h"
#ifndef OPEN_MAX #ifndef OPEN_MAX
# define OPEN_MAX 256 # define OPEN_MAX 256

85
compat/daemon-darwin.c Normal file
View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Copyright (c) 2011-2013, Chris Johnsen <chris_johnsen@pobox.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <mach/mach.h>
#include <Availability.h>
#include <unistd.h>
void daemon_darwin(void);
#ifdef __MAC_10_10
extern kern_return_t bootstrap_look_up_per_user(mach_port_t, const char *,
uid_t, mach_port_t *);
extern kern_return_t bootstrap_get_root(mach_port_t, mach_port_t *);
void
daemon_darwin(void)
{
mach_port_t root = MACH_PORT_NULL;
mach_port_t s = MACH_PORT_NULL;
uid_t uid;
uid = getuid();
if (bootstrap_get_root(bootstrap_port, &root) == KERN_SUCCESS &&
bootstrap_look_up_per_user(root, NULL, uid, &s) == KERN_SUCCESS &&
task_set_bootstrap_port(mach_task_self(), s) == KERN_SUCCESS &&
mach_port_deallocate(mach_task_self(), bootstrap_port) == KERN_SUCCESS)
bootstrap_port = s;
}
#else
void
daemon_darwin(void)
{
}
#endif

View File

@@ -28,11 +28,17 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
#include <sys/types.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include "tmux.h" #include "compat.h"
#ifdef __APPLE__
extern void daemon_darwin(void);
#endif
int int
daemon(int nochdir, int noclose) daemon(int nochdir, int noclose)
@@ -61,5 +67,9 @@ daemon(int nochdir, int noclose)
if (fd > 2) if (fd > 2)
(void)close (fd); (void)close (fd);
} }
#ifdef __APPLE__
daemon_darwin();
#endif
return (0); return (0);
} }

93
compat/err.c Normal file
View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "compat.h"
void
err(int eval, const char *fmt, ...)
{
va_list ap;
int saved_errno = errno;
fprintf(stderr, "%s: ", getprogname());
va_start(ap, fmt);
if (fmt != NULL) {
vfprintf(stderr, fmt, ap);
fprintf(stderr, ": ");
}
va_end(ap);
fprintf(stderr, "%s\n", strerror(saved_errno));
exit(eval);
}
void
errx(int eval, const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "%s: ", getprogname());
va_start(ap, fmt);
if (fmt != NULL)
vfprintf(stderr, fmt, ap);
va_end(ap);
putc('\n', stderr);
exit(eval);
}
void
warn(const char *fmt, ...)
{
va_list ap;
int saved_errno = errno;
fprintf(stderr, "%s: ", getprogname());
va_start(ap, fmt);
if (fmt != NULL) {
vfprintf(stderr, fmt, ap);
fprintf(stderr, ": ");
}
va_end(ap);
fprintf(stderr, "%s\n", strerror(saved_errno));
}
void
warnx(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "%s: ", getprogname());
va_start(ap, fmt);
if (fmt != NULL)
vfprintf(stderr, fmt, ap);
va_end(ap);
putc('\n', stderr);
}

15
compat/explicit_bzero.c Normal file
View File

@@ -0,0 +1,15 @@
/* $OpenBSD: explicit_bzero.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */
/*
* Public domain.
* Written by Matthew Dempsky.
*/
#include <string.h>
#include "compat.h"
void
explicit_bzero(void *buf, size_t len)
{
memset(buf, 0, len);
}

34
compat/fdforkpty.c Normal file
View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <limits.h>
#include "compat.h"
int
getptmfd(void)
{
return (INT_MAX);
}
pid_t
fdforkpty(__unused int ptmfd, int *master, char *name, struct termios *tio,
struct winsize *ws)
{
return (forkpty(master, name, tio, ws));
}

View File

@@ -22,7 +22,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include "tmux.h" #include "compat.h"
char * char *
fgetln(FILE *fp, size_t *len) fgetln(FILE *fp, size_t *len)

View File

@@ -23,10 +23,14 @@
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include "tmux.h" #include "compat.h"
void fatal(const char *, ...);
void fatalx(const char *, ...);
pid_t pid_t
forkpty(int *master, unused char *name, struct termios *tio, struct winsize *ws) forkpty(int *master, __unused char *name, struct termios *tio,
struct winsize *ws)
{ {
int slave = -1, fd, pipe_fd[2]; int slave = -1, fd, pipe_fd[2];
char *path, dummy; char *path, dummy;

Some files were not shown because too many files have changed in this diff Show More