1023 Commits
2.4 ... 2.9

Author SHA1 Message Date
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
Nicholas Marriott
d24a44230a Update CHANGES for 2.9. 2019-04-18 22:12:15 +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
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
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
nicm
8968acd678 Silence flag should use the same option as activity, reported by Thomas
Sattler.
2019-04-02 22:20:36 +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
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
nicm
92da105b58 Free old strings after they have been expanded in format_choose. 2019-03-29 11:19:55 +00:00
nicm
00fda57ddf Fix offset of list ranges. 2019-03-29 07:05:40 +00:00
Nicholas Marriott
e0e08fcd2d Update CHANGES & TODO. 2019-03-26 15:05:28 +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
nicm
21993105e5 Now that struct winlink has a session pointer, can remove some arguments. 2017-04-20 09:43:45 +00: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
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
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
167 changed files with 17302 additions and 9111 deletions

454
CHANGES
View File

@@ -1,4 +1,423 @@
CHANGES FROM 2.3 to 2.4 20 April 2017
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
====================
@@ -23,12 +442,12 @@ Incompatible Changes
bind -Tcopy-mode C-Up send -X scroll-up
bind -Tcopy-mode WheelUpPane send -N5 -X scroll-up
This changes allows the full command parser (including command sequences) and
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 -p'search up' "send -X search-backward '%%'"
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.
@@ -78,7 +497,7 @@ Normal Changes
set -ag syntax should work without change).
* There have been substantial performance improvements.
CHANGES FROM 2.2 to 2.3 29 September 2016
CHANGES FROM 2.2 TO 2.3, 29 September 2016
Incompatible Changes
====================
@@ -99,7 +518,7 @@ Normal Changes
* 'display-panes' can now accept a command to run, rather than always
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
====================
@@ -164,8 +583,7 @@ Normal Changes
* RGB (24bit) colour support. The 'Tc' flag must be set in the external TERM
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
====================
@@ -216,7 +634,7 @@ Normal Changes
* 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.
CHANGES FROM 1.9a to 2.0 6 March 2015
CHANGES FROM 1.9a TO 2.0, 06 March 2015
Incompatible Changes
====================
@@ -275,18 +693,18 @@ Normal Changes
* 'split-window' and 'join-window' understand -b to create the pane to the left
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.
Normal Changes
==============
* 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
advised that the prior tmux server is restarted when this version of tmux is
@@ -341,7 +759,7 @@ Normal Changes
* tmux now supports 256 colours running under fbterm.
* 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
====================
@@ -392,7 +810,7 @@ Normal Changes
* Lots and lots of bug fixes, fixing memory-leaks, etc.
* 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
end of a line.
@@ -642,7 +1060,7 @@ CHANGES FROM 1.2 TO 1.3, 18 July 2010
* Run job commands explicitly in the global environment (which can be modified
with setenv -g), rather than with the environment tmux started with.
* Use the machine's hostname as the default title, instead of an empty string.
* Prevent double free if the window option remain-on-exit is set.
* Prevent double free if the window option remain-on-exit is set.
* Key string conversions rewritten.
* Mark zombie windows as dead in the choose-window list.
* Tiled layout added.
@@ -744,7 +1162,7 @@ CHANGES FROM 1.0 TO 1.1, 05 November 2009
* New lock-client (alias lockc), and lock-session (alias locks) commands to
lock a particular client, or all clients attached to a session.
* Support C-n/C-p/C-v/M-v with emacs keys in choice mode.
* Use : for goto line rather than g in vi mode.
* Use : for goto line rather than g in vi mode.
* Try to guess which client to use when no target client was specified. Finds
the current session, and if only one client is present, use it. Otherwise,
return the most recently used client.
@@ -783,7 +1201,7 @@ CHANGES FROM 1.0 TO 1.1, 05 November 2009
* xterm-keys rewrite.
* 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.
* Backoff for a while after multiple incorrect password attempts.
@@ -875,7 +1293,7 @@ The list of older changes is below.
* main-horizontal layout and main-pane-height option to match vertical.
* New window option main-pane-width to set the width of the large left pane with
main-vertical (was left-vertical) layout.
main-vertical (was left-vertical) layout.
* Lots of layout cleanup. manual layout is now manual-vertical.
16 May 2009

View File

@@ -18,7 +18,7 @@ This should include at least the output of:
$ uname -sp && tmux -V && echo $TERM
Please do not report bugs (crashes, incorrect behaviour) without reproducing on
a tmux built from Git master.
a tmux built from the latest code in Git.
Note that TERM inside tmux must be a variant of screen or tmux (for example:
screen or screen-256color, tmux or tmux-256color). Please ensure this is the
@@ -27,7 +27,7 @@ case before opening an issue.
To run tmux without a config and get logs, run:
tmux -Ltest kill-server
tmux -vvvv -Ltest -f/dev/null new
tmux -vv -Ltest -f/dev/null new
Then reproduce the problem, exit tmux, and attach the tmux-server-*.log file
from the current directory to the issue.

462
FAQ
View File

@@ -1,462 +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, look at the pbcopy(1) and pbpaste(1) commands.
* Why don't some commands work inside tmux on OS X?
Apple requires some undocumented, unsupported fiddling to allow commands that
interact with the GUI to work. Neither tmux itself nor most shells do this, so
an external program is required. This can be found here:
https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard
Affected commands may include say(1), pbcopy(1), pbpaste(1) and ssh(1).
* 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

@@ -6,10 +6,8 @@ CLEANFILES = tmux.1.mdoc tmux.1.man
# Distribution tarball options.
EXTRA_DIST = \
CHANGES FAQ README TODO COPYING example_tmux.conf compat/*.[ch] \
CHANGES README README.ja COPYING example_tmux.conf compat/*.[ch] \
osdep-*.c mdoc2man.awk tmux.1
dist-hook:
grep "^#enable_debug=" configure
# Preprocessor flags.
AM_CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\""
@@ -68,8 +66,6 @@ dist_tmux_SOURCES = \
cmd-bind-key.c \
cmd-break-pane.c \
cmd-capture-pane.c \
cmd-choose-buffer.c \
cmd-choose-client.c \
cmd-choose-tree.c \
cmd-command-prompt.c \
cmd-confirm-before.c \
@@ -104,6 +100,7 @@ dist_tmux_SOURCES = \
cmd-rename-session.c \
cmd-rename-window.c \
cmd-resize-pane.c \
cmd-resize-window.c \
cmd-respawn-pane.c \
cmd-respawn-window.c \
cmd-rotate-window.c \
@@ -135,6 +132,7 @@ dist_tmux_SOURCES = \
control.c \
environ.c \
format.c \
format-draw.c \
grid-view.c \
grid.c \
hooks.c \
@@ -147,13 +145,13 @@ dist_tmux_SOURCES = \
layout-set.c \
layout.c \
log.c \
mode-tree.c \
names.c \
notify.c \
options-table.c \
options.c \
paste.c \
proc.c \
pty.c \
resize.c \
screen-redraw.c \
screen-write.c \
@@ -162,7 +160,6 @@ dist_tmux_SOURCES = \
server-fn.c \
server.c \
session.c \
signal.c \
status.c \
style.c \
tmux.c \
@@ -172,9 +169,11 @@ dist_tmux_SOURCES = \
tty-term.c \
tty.c \
utf8.c \
window-choose.c \
window-buffer.c \
window-client.c \
window-clock.c \
window-copy.c \
window-tree.c \
window.c \
xmalloc.c \
xmalloc.h \
@@ -198,7 +197,7 @@ install-exec-hook:
>$(srcdir)/tmux.1.mdoc; \
else \
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
$(mkdir_p) $(DESTDIR)$(mandir)/man1
$(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \

20
README
View File

@@ -1,8 +1,8 @@
Welcome to tmux!
tmux is a "terminal multiplexer", it enables a number of terminals (or windows)
to be accessed and controlled from a single terminal. tmux is intended to be a
simple, modern, BSD-licensed alternative to programs such as GNU screen.
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.
@@ -29,21 +29,19 @@ To get and build the latest from version control:
$ sh autogen.sh
$ ./configure && make
(Note that this requires at least a working C compiler, make, autoconf,
automake, pkg-config as well as libevent and ncurses libraries and headers.)
For more information see http://git-scm.com. Patches should be sent by email to
the mailing list at tmux-users@googlegroups.com.
the mailing list at tmux-users@googlegroups.com or submitted through GitHub at
https://github.com/tmux/tmux/issues.
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/ericpruitt/tmux.vim
https://raw.githubusercontent.com/ericpruitt/tmux.vim/master/vim/syntax/tmux.vim
A small example configuration in example_tmux.conf.
And a bash(1) completion file at:

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
=============================
1. Comment the "enable_debug=yes" line in configure.ac, since releases
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
1. Update and commit README and CHANGES. The former should be checked for
anything outdated and updated with a list of things that might break
upgrades and the latter should mention all the major changes since
the last version.
2. Make sure configure.ac has the new version number.
3. Tag with:
% git tag -a 2.X
@@ -157,7 +155,7 @@ Release tmux for next version
Push the tag out with:
% git push 2.X
% git push --tags
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
description field to the CHANGES file.
7. Clone the tmux.github.io repository, and change the RELEASE version in
the Makefile. Commit it, and run 'make' to replace %%VERSION%%. Push
the result out.
6. Clone the tmux.github.io repository, and change the RELEASE version in the
Makefile. Commit it, and run 'make' to replace %%RELEASE%%. Push the
result out.
8. Bump version in tmux/tmux.git configure.ac and uncomment "enable_debug=yes" to
create a debug build by default.
7. Change version back to master in configure.ac.

73
TODO
View File

@@ -1,7 +1,6 @@
- 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
@@ -17,19 +16,11 @@
* way to set socket path from config file
- format improvements:
* option to quote format (#{q:session_name})
* 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?)
* flag to choose-* for sort order
* 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)
* comparison operators like < and > (for #{version}?)
- improve monitor-*:
* straighten out rules for multiple clients
@@ -38,7 +29,7 @@
* perhaps monitor /all/ panes in the window not just one
- improve mouse support:
* bind commands to mouse in different areas?
* bind commands to mouse in different areas?
* commands executed when clicking on a pattern (URL)
- warts on current naming:
@@ -53,8 +44,15 @@
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
* improve word and line selection in copy mode (for example when dragging
it should select by word. compare how xterm works. GitHub issue 682)
* improve word and line selection in copy mode (for example when
dragging it should select by word. compare how xterm works. GitHub
issue 682)
* key to search for word under cursor (GitHub issue 1240)
* when entering copy mode, should copy grid so that input does not
need to be suspended
* allow the prefix for automatic buffers to be specified as part of the
key binding to allow session buffers or similar (GitHub issue 1501)
* copy-pipe should be synchronous (GitHub issue 1517)
- layout stuff
* way to tag a layout as a number/name
@@ -66,10 +64,11 @@
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)
* separate active panes for different clients
* way to choose where the freed space goes when a pane is killed:
option to kill-pane? GitHub issue 918
- code cleanup
* instead of separate window and session options, just one master
@@ -100,7 +99,6 @@
client w/o a session else cmd_current_client
- 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
@@ -113,10 +111,51 @@
* marks in history, automatically add (move?) one when pane is changed
* this doesn't work, need pane reference count probably:
bind -n DoubleClick3Status confirm-before -p "kill-window #I? (y/n)" kill-window
* marker lines in history (GitHub issue 1042)
* tree mode stuff: make command prompt (:) common code so all modes get it,
predefined filters, tag-all key, ...
* drag panes and windows around to move/swap them in choose mode
* flag to specify environment to new-window, split-window,
new-session (issue 1498)
* multiple column panes (issue 1503)
* support for ZERO WIDTH JOINER U+200D
* individual pane synchronize-panes (with pane options?); issue 1638
- hooks
* more hooks for various things
* finish after hooks for special commands
* finish after hooks for special commands. these do not have a hook at
the moment:
attach-session detach-client kill-server respawn-window
swap-window break-pane find-window kill-session rotate-window
switch-client choose-tree if-shell kill-window run-shell
wait-for command-prompt join-pane move-window source-file
confirm-before kill-pane respawn-pane swap-pane
at the moment AFTERHOOK uses current only if target is not valid,
but target is ALWAYS valid - it should use current if no -t flag?
then select-* could use AFTERHOOK
* multiple hooks with the same name?
* finish hooks for notifys
* for session_closed, if no sessions at all, perhaps fake up a temporary one
* for session_closed, if no sessions at all, perhaps fake up a
temporary one
- pan
* tty_window_offset should try to keep as much off active pane
visible as possible
* rather than centering cursor it might be better if only
moved offset when it gets close to an edge?
----
TODO soonish maybe:
- Store hooks as options, issue 1619.
- Support buffer prefixes, issue 1501.
- copy-pipe should be synchronous, issue 1517.
- -E flag to pass environment to new-*, issue 1498.
- Copy mode searching is slow when there is a big history, issue 1545.
- Grid "block" stuff, issue 1269. Can be used potentially for compression of
history (bit silly really though), reflow performance (can reflow blocks on
demand). It would possibly be good if history-limit could be global and
collected LRU.
- Command aliases should be able to override builtin commands in order to add
default flags (some mechanism needed to avoid recursion). GitHub issue 1630.

183
alerts.c
View File

@@ -30,13 +30,13 @@ static int alerts_enabled(struct window *, int);
static void alerts_callback(int, short, void *);
static void alerts_reset(struct window *);
static int alerts_action_applies(struct winlink *, const char *);
static int alerts_check_all(struct window *);
static int alerts_check_bell(struct window *);
static int alerts_check_activity(struct window *);
static int alerts_check_silence(struct window *);
static void printflike(2, 3) alerts_set_message(struct session *, const char *,
...);
static void alerts_ring_bell(struct session *);
static void alerts_set_message(struct winlink *, const char *,
const char *);
static TAILQ_HEAD(, window) alerts_list = TAILQ_HEAD_INITIALIZER(alerts_list);
@@ -46,7 +46,6 @@ alerts_timer(__unused int fd, __unused short events, void *arg)
struct window *w = arg;
log_debug("@%u alerts timer expired", w->id);
alerts_reset(w);
alerts_queue(w, WINDOW_SILENCE);
}
@@ -64,17 +63,38 @@ alerts_callback(__unused int fd, __unused short events, __unused void *arg)
TAILQ_REMOVE(&alerts_list, w, alerts_entry);
w->flags &= ~WINDOW_ALERTFLAGS;
window_remove_ref(w);
window_remove_ref(w, __func__);
}
alerts_fired = 0;
}
static int
alerts_action_applies(struct winlink *wl, const char *name)
{
int action;
/*
* {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.
*/
action = options_get_number(wl->session->options, name);
if (action == ALERT_ANY)
return (1);
if (action == ALERT_CURRENT)
return (wl == wl->session->curw);
if (action == ALERT_OTHER)
return (wl != wl->session->curw);
return (0);
}
static int
alerts_check_all(struct window *w)
{
int alerts;
alerts = alerts_check_bell(w);
alerts = alerts_check_bell(w);
alerts |= alerts_check_activity(w);
alerts |= alerts_check_silence(w);
return (alerts);
@@ -92,8 +112,10 @@ alerts_check_session(struct session *s)
static int
alerts_enabled(struct window *w, int flags)
{
if (flags & WINDOW_BELL)
return (1);
if (flags & WINDOW_BELL) {
if (options_get_number(w->options, "monitor-bell"))
return (1);
}
if (flags & WINDOW_ACTIVITY) {
if (options_get_number(w->options, "monitor-activity"))
return (1);
@@ -119,6 +141,9 @@ alerts_reset(struct window *w)
{
struct timeval tv;
if (!event_initialized(&w->alerts_timer))
evtimer_set(&w->alerts_timer, alerts_timer, w);
w->flags &= ~WINDOW_SILENCE;
event_del(&w->alerts_timer);
@@ -133,85 +158,61 @@ alerts_reset(struct window *w)
void
alerts_queue(struct window *w, int flags)
{
if (w->flags & WINDOW_ACTIVITY)
alerts_reset(w);
if (!event_initialized(&w->alerts_timer))
evtimer_set(&w->alerts_timer, alerts_timer, w);
alerts_reset(w);
if ((w->flags & flags) != flags) {
w->flags |= flags;
log_debug("@%u alerts flags added %#x", w->id, flags);
}
if (!w->alerts_queued) {
w->alerts_queued = 1;
TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
w->references++;
}
if (alerts_enabled(w, flags)) {
if (!w->alerts_queued) {
w->alerts_queued = 1;
TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
window_add_ref(w, __func__);
}
if (!alerts_fired && alerts_enabled(w, flags)) {
log_debug("alerts check queued (by @%u)", w->id);
event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
alerts_fired = 1;
if (!alerts_fired) {
log_debug("alerts check queued (by @%u)", w->id);
event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
alerts_fired = 1;
}
}
}
static int
alerts_check_bell(struct window *w)
{
struct window *ws;
struct winlink *wl;
struct session *s;
struct client *c;
int action, visual;
if (~w->flags & WINDOW_BELL)
return (0);
if (!options_get_number(w->options, "monitor-bell"))
return (0);
TAILQ_FOREACH(wl, &w->winlinks, wentry)
wl->session->flags &= ~SESSION_ALERTED;
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (wl->flags & WINLINK_BELL)
continue;
/*
* Bells are allowed even if there is an existing bell (so do
* not check WINLINK_BELL).
*/
s = wl->session;
if (s->curw != wl) {
wl->flags |= WINLINK_BELL;
notify_winlink("alert-bell", s, wl);
server_status_session(s);
}
if (!alerts_action_applies(wl, "bell-action"))
continue;
notify_winlink("alert-bell", wl);
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
action = options_get_number(s->options, "bell-action");
if (action == BELL_NONE)
return (0);
visual = options_get_number(s->options, "visual-bell");
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != s || c->flags & CLIENT_CONTROL)
continue;
ws = c->session->curw->window;
if (action == BELL_CURRENT && ws != w)
action = BELL_NONE;
if (action == BELL_OTHER && ws != w)
action = BELL_NONE;
if (!visual) {
if (action != BELL_NONE)
tty_putcode(&c->tty, TTYC_BEL);
continue;
}
if (action == BELL_CURRENT)
status_message_set(c, "Bell in current window");
else if (action != BELL_NONE) {
status_message_set(c, "Bell in window %d",
wl->idx);
}
}
alerts_set_message(wl, "Bell", "visual-bell");
}
return (WINDOW_BELL);
@@ -235,20 +236,19 @@ alerts_check_activity(struct window *w)
if (wl->flags & WINLINK_ACTIVITY)
continue;
s = wl->session;
if (s->curw == wl)
if (s->curw != wl) {
wl->flags |= WINLINK_ACTIVITY;
server_status_session(s);
}
if (!alerts_action_applies(wl, "activity-action"))
continue;
wl->flags |= WINLINK_ACTIVITY;
notify_winlink("alert-activity", s, wl);
notify_winlink("alert-activity", wl);
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
if (options_get_number(s->options, "bell-on-alert"))
alerts_ring_bell(s);
if (options_get_number(s->options, "visual-activity"))
alerts_set_message(s, "Activity in window %d", wl->idx);
alerts_set_message(wl, "Activity", "visual-activity");
}
return (WINDOW_ACTIVITY);
@@ -262,7 +262,7 @@ alerts_check_silence(struct window *w)
if (~w->flags & WINDOW_SILENCE)
return (0);
if (!options_get_number(w->options, "monitor-silence"))
if (options_get_number(w->options, "monitor-silence") == 0)
return (0);
TAILQ_FOREACH(wl, &w->winlinks, wentry)
@@ -272,51 +272,52 @@ alerts_check_silence(struct window *w)
if (wl->flags & WINLINK_SILENCE)
continue;
s = wl->session;
if (s->curw == wl)
if (s->curw != wl) {
wl->flags |= WINLINK_SILENCE;
server_status_session(s);
}
if (!alerts_action_applies(wl, "silence-action"))
continue;
wl->flags |= WINLINK_SILENCE;
notify_winlink("alert-silence", s, wl);
notify_winlink("alert-silence", wl);
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
if (options_get_number(s->options, "bell-on-alert"))
alerts_ring_bell(s);
if (!options_get_number(s->options, "visual-silence"))
alerts_set_message(s, "Silence in window %d", wl->idx);
alerts_set_message(wl, "Silence", "visual-silence");
}
return (WINDOW_SILENCE);
}
static void
alerts_set_message(struct session *s, const char *fmt, ...)
alerts_set_message(struct winlink *wl, const char *type, const char *option)
{
struct client *c;
va_list ap;
char *message;
int visual;
va_start(ap, fmt);
xvasprintf(&message, fmt, ap);
va_end(ap);
/*
* 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) {
if (c->session == s)
status_message_set(c, "%s", message);
}
if (c->session != wl->session || c->flags & CLIENT_CONTROL)
continue;
free(message);
}
static void
alerts_ring_bell(struct session *s)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == s && !(c->flags & CLIENT_CONTROL))
if (visual == VISUAL_OFF || visual == VISUAL_BOTH)
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

@@ -34,7 +34,6 @@ struct args_entry {
RB_ENTRY(args_entry) entry;
};
static void args_set(struct args *, u_char, const char *);
static struct args_entry *args_find(struct args *, u_char);
static int args_cmp(struct args_entry *, struct args_entry *);
@@ -191,11 +190,11 @@ args_print(struct args *args)
int
args_has(struct args *args, u_char ch)
{
return (args_find(args, ch) == NULL ? 0 : 1);
return (args_find(args, ch) != NULL);
}
/* Set argument value in the arguments tree. */
static void
void
args_set(struct args *args, u_char ch, const char *value)
{
struct args_entry *entry;

View File

@@ -25,13 +25,13 @@
const char *
attributes_tostring(int attr)
{
static char buf[128];
static char buf[512];
size_t len;
if (attr == 0)
return ("none");
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s",
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s",
(attr & GRID_ATTR_BRIGHT) ? "bright," : "",
(attr & GRID_ATTR_DIM) ? "dim," : "",
(attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "",
@@ -39,7 +39,11 @@ attributes_tostring(int attr)
(attr & GRID_ATTR_REVERSE) ? "reverse," : "",
(attr & GRID_ATTR_HIDDEN) ? "hidden," : "",
(attr & GRID_ATTR_ITALICS) ? "italics," : "",
(attr & GRID_ATTR_STRIKETHROUGH) ? "strikethrough," : "");
(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," : "");
if (len > 0)
buf[len - 1] = '\0';
@@ -52,6 +56,25 @@ attributes_fromstring(const char *str)
const char delimiters[] = " ,|";
int attr;
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 }
};
if (*str == '\0' || strcspn(str, delimiters) == 0)
return (-1);
@@ -64,24 +87,15 @@ attributes_fromstring(const char *str)
attr = 0;
do {
end = strcspn(str, delimiters);
if ((end == 6 && strncasecmp(str, "bright", end) == 0) ||
(end == 4 && strncasecmp(str, "bold", end) == 0))
attr |= GRID_ATTR_BRIGHT;
else if (end == 3 && strncasecmp(str, "dim", end) == 0)
attr |= GRID_ATTR_DIM;
else if (end == 10 && strncasecmp(str, "underscore", end) == 0)
attr |= GRID_ATTR_UNDERSCORE;
else if (end == 5 && strncasecmp(str, "blink", end) == 0)
attr |= GRID_ATTR_BLINK;
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 if (end == 13 && strncasecmp(str, "strikethrough", end) == 0)
attr |= GRID_ATTR_STRIKETHROUGH;
else
for (i = 0; i < nitems(table); i++) {
if (end != strlen(table[i].name))
continue;
if (strncasecmp(str, table[i].name, end) == 0) {
attr |= table[i].attr;
break;
}
}
if (i == nitems(table))
return (-1);
str += end + strspn(str + end, delimiters);
} while (*str != '\0');

236
cfg.c
View File

@@ -23,15 +23,34 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
static char *cfg_file;
int cfg_finished;
static char **cfg_causes;
static u_int cfg_ncauses;
struct client *cfg_client;
/* Condition for %if, %elif, %else and %endif. */
struct cfg_cond {
size_t line; /* line number of %if */
int met; /* condition was met */
int skip; /* skip later %elif/%else */
int saw_else; /* saw a %else */
TAILQ_ENTRY(cfg_cond) entry;
};
TAILQ_HEAD(cfg_conds, cfg_cond);
struct client *cfg_client;
static char *cfg_file;
int cfg_finished;
static char **cfg_causes;
static u_int cfg_ncauses;
static struct cmdq_item *cfg_item;
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)
@@ -43,8 +62,11 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data)
if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions));
if (cfg_client != NULL)
server_client_unref(cfg_client);
if (cfg_item != NULL)
cfg_item->flags &= ~CMDQ_WAITING;
status_prompt_load_history();
return (CMD_RETURN_NORMAL);
}
@@ -60,21 +82,153 @@ start_cfg(void)
{
const char *home;
int quiet = 0;
struct client *c;
cfg_client = TAILQ_FIRST(&clients);
if (cfg_client != NULL)
cfg_client->references++;
/*
* Configuration files are loaded without a client, so NULL is passed
* into load_cfg() and commands 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);
}
load_cfg(TMUX_CONF, cfg_client, NULL, 1);
load_cfg(TMUX_CONF, NULL, NULL, 1);
if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmux.conf", home);
quiet = 1;
}
if (cfg_file != NULL)
load_cfg(cfg_file, cfg_client, NULL, quiet);
load_cfg(cfg_file, NULL, NULL, quiet);
cmdq_append(cfg_client, cmdq_get_callback(cfg_done, NULL));
cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
}
static int
cfg_check_condition(const char *path, size_t line, const char *p, int *skip)
{
struct format_tree *ft;
char *s;
int result;
while (isspace((u_char)*p))
p++;
if (p[0] == '\0') {
cfg_add_cause("%s:%zu: invalid condition", path, line);
*skip = 1;
return (0);
}
ft = format_create(NULL, NULL, FORMAT_NONE, FORMAT_NOJOBS);
s = format_expand(ft, p);
result = format_true(s);
free(s);
format_free(ft);
*skip = result;
return (result);
}
static void
cfg_handle_if(const char *path, size_t line, struct cfg_conds *conds,
const char *p)
{
struct cfg_cond *cond;
struct cfg_cond *parent = TAILQ_FIRST(conds);
/*
* Add a new condition. If a previous condition exists and isn't
* currently met, this new one also can't be met.
*/
cond = xcalloc(1, sizeof *cond);
cond->line = line;
if (parent == NULL || parent->met)
cond->met = cfg_check_condition(path, line, p, &cond->skip);
else
cond->skip = 1;
cond->saw_else = 0;
TAILQ_INSERT_HEAD(conds, cond, entry);
}
static void
cfg_handle_elif(const char *path, size_t line, struct cfg_conds *conds,
const char *p)
{
struct cfg_cond *cond = TAILQ_FIRST(conds);
/*
* If a previous condition exists and wasn't met, check this
* one instead and change the state.
*/
if (cond == NULL || cond->saw_else)
cfg_add_cause("%s:%zu: unexpected %%elif", path, line);
else if (!cond->skip)
cond->met = cfg_check_condition(path, line, p, &cond->skip);
else
cond->met = 0;
}
static void
cfg_handle_else(const char *path, size_t line, struct cfg_conds *conds)
{
struct cfg_cond *cond = TAILQ_FIRST(conds);
/*
* If a previous condition exists and wasn't met and wasn't already
* %else, use this one instead.
*/
if (cond == NULL || cond->saw_else) {
cfg_add_cause("%s:%zu: unexpected %%else", path, line);
return;
}
cond->saw_else = 1;
cond->met = !cond->skip;
cond->skip = 1;
}
static void
cfg_handle_endif(const char *path, size_t line, struct cfg_conds *conds)
{
struct cfg_cond *cond = TAILQ_FIRST(conds);
/*
* Remove previous condition if one exists.
*/
if (cond == NULL) {
cfg_add_cause("%s:%zu: unexpected %%endif", path, line);
return;
}
TAILQ_REMOVE(conds, cond, entry);
free(cond);
}
static void
cfg_handle_directive(const char *p, const char *path, size_t line,
struct cfg_conds *conds)
{
int n = 0;
while (p[n] != '\0' && !isspace((u_char)p[n]))
n++;
if (strncmp(p, "%if", n) == 0)
cfg_handle_if(path, line, conds, p + n);
else if (strncmp(p, "%elif", n) == 0)
cfg_handle_elif(path, line, conds, p + n);
else if (strcmp(p, "%else") == 0)
cfg_handle_else(path, line, conds);
else if (strcmp(p, "%endif") == 0)
cfg_handle_endif(path, line, conds);
else
cfg_add_cause("%s:%zu: invalid directive: %s", path, line, p);
}
int
@@ -84,11 +238,13 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
const char delim[3] = { '\\', '\\', '\0' };
u_int found = 0;
size_t line = 0;
char *buf, *cause1, *p, *q, *s;
char *buf, *cause1, *p, *q;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
int condition = 0;
struct format_tree *ft;
struct cfg_cond *cond, *cond1;
struct cfg_conds conds;
TAILQ_INIT(&conds);
log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) {
@@ -112,32 +268,12 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
while (q != p && isspace((u_char)*q))
*q-- = '\0';
if (condition != 0 && strcmp(p, "%endif") == 0) {
condition = 0;
if (*p == '%') {
cfg_handle_directive(p, path, line, &conds);
continue;
}
if (strncmp(p, "%if ", 4) == 0) {
if (condition != 0) {
cfg_add_cause("%s:%zu: nested %%if", path,
line);
continue;
}
ft = format_create(NULL, FORMAT_NONE, FORMAT_NOJOBS);
s = p + 3;
while (isspace((u_char)*s))
s++;
s = format_expand(ft, s);
if (*s != '\0' && (s[0] != '0' || s[1] != '\0'))
condition = 1;
else
condition = -1;
free(s);
format_free(ft);
continue;
}
if (condition == -1)
cond = TAILQ_FIRST(&conds);
if (cond != NULL && !cond->met)
continue;
cmdlist = cmd_string_parse(p, path, line, &cause1);
@@ -151,8 +287,6 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
}
free(buf);
if (cmdlist == NULL)
continue;
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
if (item != NULL)
cmdq_insert_after(item, new_item);
@@ -164,6 +298,12 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
}
fclose(f);
TAILQ_FOREACH_REVERSE_SAFE(cond, &conds, cfg_conds, entry, cond1) {
cfg_add_cause("%s:%zu: unterminated %%if", path, cond->line);
TAILQ_REMOVE(&conds, cond, entry);
free(cond);
}
return (found);
}
@@ -200,15 +340,17 @@ cfg_print_causes(struct cmdq_item *item)
void
cfg_show_causes(struct session *s)
{
struct window_pane *wp;
u_int i;
struct window_pane *wp;
struct window_mode_entry *wme;
u_int i;
if (s == NULL || cfg_ncauses == 0)
return;
wp = s->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp);
wme = TAILQ_FIRST(&wp->modes);
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++) {
window_copy_add(wp, "%s", cfg_causes[i]);
free(cfg_causes[i]);

View File

@@ -17,11 +17,10 @@
*/
#include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <errno.h>
#include <event.h>
@@ -63,7 +62,7 @@ static void client_write(int, const char *, size_t);
static void client_signal(int);
static void client_dispatch(struct imsg *, void *);
static void client_dispatch_attached(struct imsg *);
static void client_dispatch_wait(struct imsg *, const char *);
static void client_dispatch_wait(struct imsg *);
static const char *client_exit_message(void);
/*
@@ -156,7 +155,7 @@ retry:
close(lockfd);
return (-1);
}
fd = server_start(base, lockfd, lockfile);
fd = server_start(client_proc, base, lockfd, lockfile);
}
if (locked && lockfd >= 0) {
@@ -214,8 +213,7 @@ client_exit_message(void)
/* Client main loop. */
int
client_main(struct event_base *base, int argc, char **argv, int flags,
const char *shellcmd)
client_main(struct event_base *base, int argc, char **argv, int flags)
{
struct cmd *cmd;
struct cmd_list *cmdlist;
@@ -224,7 +222,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
const char *ttynam, *cwd;
pid_t ppid;
enum msgtype msg;
char *cause, path[PATH_MAX];
char *cause;
struct termios tio, saved_tio;
size_t size;
@@ -236,7 +234,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
/* Set up the initial command. */
cmdflags = 0;
if (shellcmd != NULL) {
if (shell_command != NULL) {
msg = MSG_SHELL;
cmdflags = CMD_STARTSERVER;
} else if (argc == 0) {
@@ -261,7 +259,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
}
/* 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. */
fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
@@ -275,14 +274,11 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
}
return (1);
}
client_peer = proc_add_peer(client_proc, fd, client_dispatch,
(void *)shellcmd);
client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL);
/* Save these before pledge(). */
if ((cwd = getcwd(path, sizeof path)) == NULL) {
if ((cwd = find_home()) == NULL)
cwd = "/";
}
if ((cwd = find_cwd()) == NULL && (cwd = find_home()) == NULL)
cwd = "/";
if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
ttynam = "";
@@ -339,6 +335,10 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
size = 0;
for (i = 0; i < argc; i++)
size += strlen(argv[i]) + 1;
if (size > MAX_IMSGSIZE - (sizeof *data)) {
fprintf(stderr, "command too long\n");
return (1);
}
data = xmalloc((sizeof *data) + size);
/* Prepare command for server. */
@@ -367,7 +367,6 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
if (client_exittype == MSG_EXEC) {
if (client_flags & CLIENT_CONTROLCONTROL)
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
clear_signals(0);
client_exec(client_execshell, client_execcmd);
}
@@ -451,6 +450,7 @@ client_write(int fd, const char *data, size_t size)
{
ssize_t used;
log_debug("%s: %.*s", __func__, (int)size, data);
while (size != 0) {
used = write(fd, data, size);
if (used == -1) {
@@ -483,6 +483,8 @@ client_exec(const char *shell, const char *shellcmd)
xasprintf(&argv0, "%s", name);
setenv("SHELL", shell, 1);
proc_clear_signals(client_proc, 1);
setblocking(STDIN_FILENO, 1);
setblocking(STDOUT_FILENO, 1);
setblocking(STDERR_FILENO, 1);
@@ -534,7 +536,7 @@ client_signal(int sig)
/* Callback for client read events. */
static void
client_dispatch(struct imsg *imsg, void *arg)
client_dispatch(struct imsg *imsg, __unused void *arg)
{
if (imsg == NULL) {
client_exitreason = CLIENT_EXIT_LOST_SERVER;
@@ -546,12 +548,12 @@ client_dispatch(struct imsg *imsg, void *arg)
if (client_attached)
client_dispatch_attached(imsg);
else
client_dispatch_wait(imsg, arg);
client_dispatch_wait(imsg);
}
/* Dispatch imsgs when in wait state (before MSG_READY). */
static void
client_dispatch_wait(struct imsg *imsg, const char *shellcmd)
client_dispatch_wait(struct imsg *imsg)
{
char *data;
ssize_t datalen;
@@ -630,8 +632,7 @@ client_dispatch_wait(struct imsg *imsg, const char *shellcmd)
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_SHELL string");
clear_signals(0);
client_exec(data, shellcmd);
client_exec(data, shell_command);
/* NOTREACHED */
case MSG_DETACH:
case MSG_DETACHKILL:

View File

@@ -40,20 +40,23 @@ const struct cmd_entry cmd_attach_session_entry = {
.args = { "c:dErt:", 0, 0 },
.usage = "[-dEr] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION_WITHPANE,
/* -t is special */
.flags = CMD_STARTSERVER,
.exec = cmd_attach_session_exec
};
enum cmd_retval
cmd_attach_session(struct cmdq_item *item, int dflag, int rflag,
const char *cflag, int Eflag)
cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
int rflag, const char *cflag, int Eflag)
{
struct session *s = item->state.tflag.s;
struct cmd_find_state *current = &item->shared->current;
enum cmd_find_type type;
int flags;
struct client *c = item->client, *c_loop;
struct winlink *wl = item->state.tflag.wl;
struct window_pane *wp = item->state.tflag.wp;
struct session *s;
struct winlink *wl;
struct window_pane *wp;
char *cause;
if (RB_EMPTY(&sessions)) {
@@ -69,10 +72,27 @@ cmd_attach_session(struct cmdq_item *item, int dflag, int rflag,
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 (wp != NULL)
window_set_active_pane(wp->window, wp);
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) {
@@ -80,6 +100,7 @@ cmd_attach_session(struct cmdq_item *item, int dflag, int rflag,
s->cwd = format_single(item, cflag, c, s, wl, wp);
}
c->last_session = c->session;
if (c->session != NULL) {
if (dflag) {
TAILQ_FOREACH(c_loop, &clients, entry) {
@@ -92,8 +113,9 @@ cmd_attach_session(struct cmdq_item *item, int dflag, int rflag,
environ_update(s->options, c->environ, s->environ);
c->session = s;
if (!item->repeat)
if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
@@ -121,6 +143,7 @@ cmd_attach_session(struct cmdq_item *item, int dflag, int rflag,
c->session = s;
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
@@ -145,6 +168,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
return (cmd_attach_session(item, args_has(args, 'd'),
args_has(args, 'r'), args_get(args, 'c'), args_has(args, 'E')));
return (cmd_attach_session(item, args_get(args, 't'),
args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c'),
args_has(args, 'E')));
}

View File

@@ -35,10 +35,11 @@ const struct cmd_entry cmd_break_pane_entry = {
.alias = "breakp",
.args = { "dPF:n:s:t:", 0, 0 },
.usage = "[-dP] [-F format] [-n window-name] [-s src-pane] [-t dst-window]",
.usage = "[-dP] [-F format] [-n window-name] [-s src-pane] "
"[-t dst-window]",
.sflag = CMD_PANE,
.tflag = CMD_WINDOW_INDEX,
.source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
.flags = 0,
.exec = cmd_break_pane_exec
@@ -48,14 +49,15 @@ static enum cmd_retval
cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct winlink *wl = item->state.sflag.wl;
struct session *src_s = item->state.sflag.s;
struct session *dst_s = item->state.tflag.s;
struct window_pane *wp = item->state.sflag.wp;
struct cmd_find_state *current = &item->shared->current;
struct client *c = cmd_find_client(item, NULL, 1);
struct winlink *wl = item->source.wl;
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;
char *name, *cause;
int idx = item->state.tflag.idx;
int idx = item->target.idx;
const char *template;
char *cp;
@@ -74,7 +76,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
window_lost_pane(w, wp);
layout_close_pane(wp);
w = wp->window = window_create(dst_s->sx, dst_s->sy);
w = wp->window = window_create(w->sx, w->sy);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp;
@@ -93,8 +95,10 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
if (idx == -1)
idx = -1 - options_get_number(dst_s->options, "base-index");
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);
cmd_find_from_session(current, dst_s, 0);
}
server_redraw_session(src_s);
if (src_s != dst_s)

View File

@@ -41,9 +41,9 @@ const struct cmd_entry cmd_capture_pane_entry = {
.args = { "ab:CeE:JpPqS:t:", 0, 0 },
.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 = CMD_AFTERHOOK,
.exec = cmd_capture_pane_exec
@@ -56,7 +56,7 @@ const struct cmd_entry cmd_clear_history_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_capture_pane_exec
@@ -193,14 +193,13 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
struct window_pane *wp = item->state.tflag.wp;
struct window_pane *wp = item->target.wp;
char *buf, *cause;
const char *bufname;
size_t len;
if (self->entry == &cmd_clear_history_entry) {
if (wp->mode == &window_copy_mode)
window_pane_reset_mode(wp);
window_pane_reset_mode_all(wp);
grid_clear_history(wp->base.grid);
return (CMD_RETURN_NORMAL);
}

View File

@@ -1,101 +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}"
static enum cmd_retval cmd_choose_buffer_exec(struct cmd *,
struct cmdq_item *);
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
};
static enum cmd_retval
cmd_choose_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct winlink *wl = item->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(item, "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,135 +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_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}]" \
"#{?client_utf8, (utf8),}#{?client_readonly, (ro),} " \
"(last used #{t:client_activity})"
static enum cmd_retval cmd_choose_client_exec(struct cmd *,
struct cmdq_item *);
static 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;
};
static enum cmd_retval
cmd_choose_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct client *c1;
struct window_choose_data *cdata;
struct winlink *wl = item->state.tflag.wl;
const char *template;
char *action;
u_int idx, cur;
if (c == NULL) {
cmdq_error(item, "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)
continue;
if (c1 == item->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->name, 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);
}
static 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,66 +18,51 @@
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.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 \
"#{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}\""
static enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_choose_tree_entry = {
.name = "choose-tree",
.alias = NULL,
.args = { "S:W:swub:c:t:", 0, 1 },
.usage = "[-suw] [-b session-template] [-c window template] "
"[-S format] [-W format] " CMD_TARGET_WINDOW_USAGE,
.args = { "F:Gf:NO:st:wZ", 0, 1 },
.usage = "[-GNsw] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_choose_tree_exec
};
const struct cmd_entry cmd_choose_session_entry = {
.name = "choose-session",
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]",
.args = { "F:f:NO:t:Z", 0, 1 },
.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,
.exec = cmd_choose_tree_exec
};
const struct cmd_entry cmd_choose_window_entry = {
.name = "choose-window",
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]",
.args = { "F:f:NO:t:Z", 0, 1 },
.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,
.exec = cmd_choose_tree_exec
@@ -87,167 +72,20 @@ static enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct winlink *wl = item->state.tflag.wl, *wm;
struct session *s = item->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;
struct window_pane *wp = item->target.wp;
const struct window_mode *mode;
ses_template = win_template = NULL;
ses_action = win_action = NULL;
if (c == NULL) {
cmdq_error(item, "no client available");
return (CMD_RETURN_ERROR);
}
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);
if (self->entry == &cmd_choose_buffer_entry) {
if (paste_get_top(NULL) == NULL)
return (CMD_RETURN_NORMAL);
mode = &window_buffer_mode;
} else if (self->entry == &cmd_choose_client_entry) {
if (server_client_how_many() == 0)
return (CMD_RETURN_NORMAL);
mode = &window_client_mode;
} else
final_win_template_middle = final_win_template_last = NULL;
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);
}
mode = &window_tree_mode;
window_pane_set_mode(wp, mode, &item->target, args);
return (CMD_RETURN_NORMAL);
}

View File

@@ -32,7 +32,8 @@
static enum cmd_retval cmd_command_prompt_exec(struct cmd *,
struct cmdq_item *);
static int cmd_command_prompt_callback(void *, const char *, int);
static int cmd_command_prompt_callback(struct client *, void *,
const char *, int);
static void cmd_command_prompt_free(void *);
const struct cmd_entry cmd_command_prompt_entry = {
@@ -43,24 +44,21 @@ const struct cmd_entry cmd_command_prompt_entry = {
.usage = "[-1Ni] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
"[template]",
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_command_prompt_exec
};
struct cmd_command_prompt_cdata {
struct client *c;
int flags;
int flags;
char *inputs;
char *next_input;
char *inputs;
char *next_input;
char *prompts;
char *next_prompt;
char *prompts;
char *next_prompt;
char *template;
int idx;
char *template;
int idx;
};
static enum cmd_retval
@@ -69,15 +67,17 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
struct args *args = self->args;
const char *inputs, *prompts;
struct cmd_command_prompt_cdata *cdata;
struct client *c = item->state.c;
struct client *c;
char *prompt, *ptr, *input = NULL;
size_t n;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (c->prompt_string != NULL)
return (CMD_RETURN_NORMAL);
cdata = xcalloc(1, sizeof *cdata);
cdata->c = c;
cdata->inputs = NULL;
cdata->next_input = NULL;
@@ -141,10 +141,10 @@ cmd_command_prompt_error(struct cmdq_item *item, void *data)
}
static int
cmd_command_prompt_callback(void *data, const char *s, int done)
cmd_command_prompt_callback(struct client *c, void *data, const char *s,
int done)
{
struct cmd_command_prompt_cdata *cdata = data;
struct client *c = cdata->c;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
char *cause, *new_template, *prompt, *ptr;
@@ -192,7 +192,7 @@ cmd_command_prompt_callback(void *data, const char *s, int done)
if (!done)
free(new_template);
if (c->prompt_callbackfn != (void *)&cmd_command_prompt_callback)
if (c->prompt_inputcb != cmd_command_prompt_callback)
return (1);
return (0);
}

View File

@@ -31,7 +31,8 @@
static enum cmd_retval cmd_confirm_before_exec(struct cmd *,
struct cmdq_item *);
static int cmd_confirm_before_callback(void *, const char *, int);
static int cmd_confirm_before_callback(struct client *, void *,
const char *, int);
static void cmd_confirm_before_free(void *);
const struct cmd_entry cmd_confirm_before_entry = {
@@ -41,15 +42,12 @@ const struct cmd_entry cmd_confirm_before_entry = {
.args = { "p:t:", 1, 1 },
.usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_confirm_before_exec
};
struct cmd_confirm_before_data {
char *cmd;
struct client *client;
char *cmd;
};
static enum cmd_retval
@@ -57,10 +55,13 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_confirm_before_data *cdata;
struct client *c = item->state.c;
struct client *c;
char *cmd, *copy, *new_prompt, *ptr;
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)
xasprintf(&new_prompt, "%s ", prompt);
else {
@@ -73,9 +74,6 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[0]);
cdata->client = c;
cdata->client->references++;
status_prompt_set(c, new_prompt, NULL,
cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
PROMPT_SINGLE);
@@ -96,10 +94,10 @@ cmd_confirm_before_error(struct cmdq_item *item, void *data)
}
static int
cmd_confirm_before_callback(void *data, const char *s, __unused int done)
cmd_confirm_before_callback(struct client *c, void *data, const char *s,
__unused int done)
{
struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
char *cause;
@@ -134,9 +132,6 @@ static void
cmd_confirm_before_free(void *data)
{
struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client;
server_client_unref(c);
free(cdata->cmd);
free(cdata);

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_copy_mode_entry = {
.args = { "Met:u", 0, 0 },
.usage = "[-Mu] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_copy_mode_exec
@@ -46,7 +46,7 @@ const struct cmd_entry cmd_clock_mode_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_copy_mode_exec
@@ -56,33 +56,28 @@ static enum cmd_retval
cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmdq_shared *shared = item->shared;
struct client *c = item->client;
struct session *s;
struct window_pane *wp = item->state.tflag.wp;
struct window_pane *wp = item->target.wp;
if (args_has(args, 'M')) {
if ((wp = cmd_mouse_pane(&item->mouse, &s, NULL)) == NULL)
if ((wp = cmd_mouse_pane(&shared->mouse, &s, NULL)) == NULL)
return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
}
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);
}
if (wp->mode != &window_copy_mode) {
if (window_pane_set_mode(wp, &window_copy_mode) != 0)
return (CMD_RETURN_NORMAL);
window_copy_init_from_pane(wp, args_has(self->args, 'e'));
}
if (args_has(args, 'M')) {
if (wp->mode != NULL && wp->mode != &window_copy_mode)
return (CMD_RETURN_NORMAL);
window_copy_start_drag(c, &item->mouse);
}
if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
if (window_pane_set_mode(wp, &window_copy_mode, NULL, args) != 0)
return (CMD_RETURN_NORMAL);
if (args_has(args, 'M'))
window_copy_start_drag(c, &shared->mouse);
if (args_has(self->args, 'u'))
window_copy_pageup(wp, 0);
return (CMD_RETURN_NORMAL);

View File

@@ -37,8 +37,7 @@ const struct cmd_entry cmd_detach_client_entry = {
.usage = "[-aP] [-E shell-command] "
"[-s target-session] " CMD_TARGET_CLIENT_USAGE,
.sflag = CMD_SESSION,
.tflag = CMD_CLIENT,
.source = { 's', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_READONLY,
.exec = cmd_detach_client_exec
@@ -51,8 +50,6 @@ const struct cmd_entry cmd_suspend_client_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_detach_client_exec
};
@@ -61,15 +58,16 @@ static enum cmd_retval
cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c, *cloop;
struct client *c, *cloop;
struct session *s;
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) {
tty_stop_tty(&c->tty);
c->flags |= CLIENT_SUSPENDED;
proc_send(c->peer, MSG_SUSPEND, -1, NULL, 0);
server_client_suspend(c);
return (CMD_RETURN_NORMAL);
}
@@ -79,7 +77,9 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
msgtype = MSG_DETACH;
if (args_has(args, 's')) {
s = item->state.sflag.s;
s = item->source.s;
if (s == NULL)
return (CMD_RETURN_NORMAL);
TAILQ_FOREACH(cloop, &clients, entry) {
if (cloop->session == s) {
if (cmd != NULL)

View File

@@ -39,28 +39,36 @@ const struct cmd_entry cmd_display_message_entry = {
.name = "display-message",
.alias = "display",
.args = { "c:pt:F:", 0, 1 },
.usage = "[-p] [-c target-client] [-F format] "
.args = { "ac:pt:F:v", 0, 1 },
.usage = "[-apv] [-c target-client] [-F format] "
CMD_TARGET_PANE_USAGE " [message]",
.cflag = CMD_CLIENT_CANFAIL,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_display_message_exec
};
static void
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 client *c = item->state.c;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct window_pane *wp = item->state.tflag.wp;
struct client *c, *target_c;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
const char *template;
char *msg;
struct format_tree *ft;
int flags;
if (args_has(args, 'F') && args->argc != 0) {
cmdq_error(item, "only one of -F or argument must be given");
@@ -73,10 +81,31 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
if (template == NULL)
template = DISPLAY_MESSAGE_TEMPLATE;
ft = format_create(item, FORMAT_NONE, 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')) {
if (item != NULL)
format_each(ft, cmd_display_message_each, item);
return (CMD_RETURN_NORMAL);
}
msg = format_expand_time(ft, template);
if (args_has(self->args, 'p'))
cmdq_print(item, "%s", msg);
else if (c != NULL)

View File

@@ -37,10 +37,8 @@ const struct cmd_entry cmd_display_panes_entry = {
.name = "display-panes",
.alias = "displayp",
.args = { "t:", 0, 1 },
.usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.args = { "bd:t:", 0, 1 },
.usage = "[-b] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
.flags = CMD_AFTERHOOK,
.exec = cmd_display_panes_exec
@@ -50,7 +48,14 @@ static enum cmd_retval
cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct client *c;
struct session *s;
u_int delay;
char *cause;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
s = c->session;
if (c->identify_callback != NULL)
return (CMD_RETURN_NORMAL);
@@ -60,10 +65,25 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
c->identify_callback_data = xstrdup(args->argv[0]);
else
c->identify_callback_data = xstrdup("select-pane -t '%%'");
if (args_has(args, 'b'))
c->identify_callback_item = NULL;
else
c->identify_callback_item = item;
server_client_set_identify(c);
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");
server_client_set_identify(c, delay);
return (CMD_RETURN_NORMAL);
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
static enum cmd_retval
@@ -82,34 +102,42 @@ cmd_display_panes_callback(struct client *c, struct window_pane *wp)
{
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
char *template, *cmd, *expanded, *cause;
char *cmd, *expanded, *cause;
template = c->identify_callback_data;
if (wp == NULL)
goto out;
xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(template, expanded, 1);
cmd = cmd_template_replace(c->identify_callback_data, expanded, 1);
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
if (cmdlist == NULL) {
if (cause != NULL) {
new_item = cmdq_get_callback(cmd_display_panes_error,
cause);
} else
new_item = NULL;
} else {
if (cmdlist == NULL && cause != NULL)
new_item = cmdq_get_callback(cmd_display_panes_error, cause);
else if (cmdlist == NULL)
new_item = NULL;
else {
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
}
if (new_item != NULL)
cmdq_append(c, new_item);
if (new_item != NULL) {
if (c->identify_callback_item != NULL)
cmdq_insert_after(c->identify_callback_item, new_item);
else
cmdq_append(c, new_item);
}
free(cmd);
free(expanded);
out:
if (c->identify_callback_item != NULL) {
c->identify_callback_item->flags &= ~CMDQ_WAITING;
c->identify_callback_item = NULL;
}
free(c->identify_callback_data);
c->identify_callback_data = NULL;
c->identify_callback = NULL;
}

View File

@@ -18,9 +18,7 @@
#include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -28,213 +26,71 @@
* Find window containing text.
*/
#define FIND_WINDOW_TEMPLATE \
"#{window_index}: #{window_name} " \
"[#{window_width}x#{window_height}] " \
"(#{window_panes} panes) #{window_find_matches}"
static enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmdq_item *);
static 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 = {
.name = "find-window",
.alias = "findw",
.args = { "F:CNt:T", 1, 4 },
.usage = "[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string",
.args = { "CNt:TZ", 1, 1 },
.usage = "[-CNTZ] " CMD_TARGET_PANE_USAGE " match-string",
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_find_window_exec
};
struct cmd_find_window_data {
struct winlink *wl;
char *list_ctx;
u_int pane_id;
TAILQ_ENTRY(cmd_find_window_data) entry;
};
TAILQ_HEAD(cmd_find_window_list, cmd_find_window_data);
static u_int cmd_find_window_match_flags(struct args *);
static void cmd_find_window_match(struct cmd_find_window_list *, int,
struct winlink *, const char *, const char *);
static u_int
cmd_find_window_match_flags(struct args *args)
{
u_int match_flags = 0;
/* Turn on flags based on the options. */
if (args_has(args, 'T'))
match_flags |= CMD_FIND_WINDOW_BY_TITLE;
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 (match_flags == 0)
match_flags = CMD_FIND_WINDOW_ALL;
return (match_flags);
}
static void
cmd_find_window_match(struct cmd_find_window_list *find_list,
int match_flags, struct winlink *wl, const char *str,
const char *searchstr)
{
struct cmd_find_window_data *find_data;
struct window_pane *wp;
u_int i, line;
char *sres;
find_data = xcalloc(1, sizeof *find_data);
i = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
i++;
if ((match_flags & CMD_FIND_WINDOW_BY_NAME) &&
fnmatch(searchstr, wl->window->name, 0) == 0) {
find_data->list_ctx = xstrdup("");
break;
}
if ((match_flags & CMD_FIND_WINDOW_BY_TITLE) &&
fnmatch(searchstr, wp->base.title, 0) == 0) {
xasprintf(&find_data->list_ctx,
"pane %u title: \"%s\"", i - 1, wp->base.title);
break;
}
if (match_flags & CMD_FIND_WINDOW_BY_CONTENT &&
(sres = window_pane_search(wp, str, &line)) != NULL) {
xasprintf(&find_data->list_ctx,
"pane %u line %u: \"%s\"", i - 1, line + 1, sres);
free(sres);
break;
}
}
if (find_data->list_ctx != NULL) {
find_data->wl = wl;
find_data->pane_id = i - 1;
TAILQ_INSERT_TAIL(find_list, find_data, entry);
} else
free(find_data);
}
static enum cmd_retval
cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct window_choose_data *cdata;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->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;
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;
if (c == NULL) {
cmdq_error(item, "no client available");
return (CMD_RETURN_ERROR);
}
C = args_has(args, 'C');
N = args_has(args, 'N');
T = args_has(args, 'T');
if ((template = args_get(args, 'F')) == NULL)
template = FIND_WINDOW_TEMPLATE;
if (!C && !N && !T)
C = N = T = 1;
match_flags = cmd_find_window_match_flags(args);
str = args->argv[0];
if (C && N && T) {
xasprintf(&filter,
"#{||:"
"#{C:%s},#{||:#{m:*%s*,#{window_name}},"
"#{m:*%s*,#{pane_title}}}}",
s, s, s);
} else if (C && N) {
xasprintf(&filter,
"#{||:#{C:%s},#{m:*%s*,#{window_name}}}",
s, s);
} else if (C && T) {
xasprintf(&filter,
"#{||:#{C:%s},#{m:*%s*,#{pane_title}}}",
s, s);
} else if (N && T) {
xasprintf(&filter,
"#{||:#{m:*%s*,#{window_name}},#{m:*%s*,#{pane_title}}}",
s, s);
} else if (C)
xasprintf(&filter, "#{C:%s}", s);
else if (N)
xasprintf(&filter, "#{m:*%s*,#{window_name}}", s);
else
xasprintf(&filter, "#{m:*%s*,#{pane_title}}", s);
TAILQ_INIT(&find_list);
new_args = args_parse("", 1, &argv);
if (args_has(args, 'Z'))
args_set(new_args, 'Z', NULL);
args_set(new_args, 'f', filter);
xasprintf(&searchstr, "*%s*", str);
RB_FOREACH(wm, winlinks, &s->windows)
cmd_find_window_match(&find_list, match_flags, wm, str, searchstr);
free(searchstr);
window_pane_set_mode(wp, &window_tree_mode, &item->target, new_args);
if (TAILQ_EMPTY(&find_list)) {
cmdq_error(item, "no windows matching: %s", str);
return (CMD_RETURN_ERROR);
}
args_free(new_args);
free(filter);
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);
}
static 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();
}
}

View File

@@ -26,21 +26,15 @@
#include "tmux.h"
static struct session *cmd_find_try_TMUX(struct client *, struct window *);
static int cmd_find_client_better(struct client *, struct client *);
static struct client *cmd_find_best_client(struct client **, u_int);
static int cmd_find_session_better(struct session *, struct session *,
int);
static struct session *cmd_find_best_session(struct session **, u_int, int);
static int cmd_find_best_session_with_window(struct cmd_find_state *);
static int cmd_find_best_winlink_with_window(struct cmd_find_state *);
static int cmd_find_current_session_with_client(struct cmd_find_state *);
static int cmd_find_current_session(struct cmd_find_state *);
static struct client *cmd_find_current_client(struct cmdq_item *);
static const char *cmd_find_map_table(const char *[][2], const char *);
static void cmd_find_log_state(const char *, struct cmd_find_state *);
static int cmd_find_get_session(struct cmd_find_state *, const char *);
static int cmd_find_get_window(struct cmd_find_state *, const char *, int);
static int cmd_find_get_window_with_session(struct cmd_find_state *,
@@ -83,7 +77,7 @@ static const char *cmd_find_pane_table[][2] = {
/* Get session from TMUX if present. */
static struct session *
cmd_find_try_TMUX(struct client *c, struct window *w)
cmd_find_try_TMUX(struct client *c)
{
struct environ_entry *envent;
char tmp[256];
@@ -99,15 +93,33 @@ cmd_find_try_TMUX(struct client *c, struct window *w)
return (NULL);
if (pid != getpid())
return (NULL);
log_debug("client %p TMUX is %s (session @%u)", c, envent->value,
session);
log_debug("%s: client %p TMUX %s (session $%u)", __func__, c,
envent->value, session);
s = session_find_by_id(session);
if (s == NULL || (w != NULL && !session_has(s, w)))
return (NULL);
if (s != NULL)
log_debug("%s: session $%u still exists", __func__, s->id);
return (s);
}
/* Find pane containing client if any. */
static struct window_pane *
cmd_find_inside_pane(struct client *c)
{
struct window_pane *wp;
if (c == NULL)
return (NULL);
RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
if (wp->fd != -1 && strcmp(wp->tty, c->ttyname) == 0)
break;
}
if (wp != NULL)
log_debug("%s: got pane %%%u (%s)", __func__, wp->id, wp->tty);
return (wp);
}
/* Is this client better? */
static int
cmd_find_client_better(struct client *c, struct client *than)
@@ -117,28 +129,23 @@ cmd_find_client_better(struct client *c, struct client *than)
return (timercmp(&c->activity_time, &than->activity_time, >));
}
/* Find best client from a list, or all if list is NULL. */
static struct client *
cmd_find_best_client(struct client **clist, u_int csize)
/* Find best client for session. */
struct client *
cmd_find_best_client(struct session *s)
{
struct client *c_loop, *c;
u_int i;
if (s->attached == 0)
s = NULL;
c = NULL;
if (clist != NULL) {
for (i = 0; i < csize; i++) {
if (clist[i]->session == NULL)
continue;
if (cmd_find_client_better(clist[i], c))
c = clist[i];
}
} else {
TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session == NULL)
continue;
if (cmd_find_client_better(c_loop, c))
c = c_loop;
}
TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session == NULL)
continue;
if (s != NULL && c_loop->session != s)
continue;
if (cmd_find_client_better(c_loop, c))
c = c_loop;
}
return (c);
}
@@ -152,10 +159,10 @@ cmd_find_session_better(struct session *s, struct session *than, int flags)
if (than == NULL)
return (1);
if (flags & CMD_FIND_PREFER_UNATTACHED) {
attached = (~than->flags & SESSION_UNATTACHED);
if (attached && (s->flags & SESSION_UNATTACHED))
attached = (than->attached != 0);
if (attached && s->attached == 0)
return (1);
else if (!attached && (~s->flags & SESSION_UNATTACHED))
else if (!attached && s->attached != 0)
return (0);
}
return (timercmp(&s->activity_time, &than->activity_time, >));
@@ -168,6 +175,8 @@ cmd_find_best_session(struct session **slist, u_int ssize, int flags)
struct session *s_loop, *s;
u_int i;
log_debug("%s: %u sessions to try", __func__, ssize);
s = NULL;
if (slist != NULL) {
for (i = 0; i < ssize; i++) {
@@ -191,11 +200,7 @@ cmd_find_best_session_with_window(struct cmd_find_state *fs)
u_int ssize;
struct session *s;
if (fs->item != NULL && fs->item->client != NULL) {
fs->s = cmd_find_try_TMUX(fs->item->client, fs->w);
if (fs->s != NULL)
return (cmd_find_best_winlink_with_window(fs));
}
log_debug("%s: window is @%u", __func__, fs->w->id);
ssize = 0;
RB_FOREACH(s, sessions, &sessions) {
@@ -218,7 +223,7 @@ fail:
}
/*
* Find the best winlink for a window (the current if it contains the pane,
* Find the best winlink for a window (the current if it contains the window,
* otherwise the first).
*/
static int
@@ -226,6 +231,8 @@ cmd_find_best_winlink_with_window(struct cmd_find_state *fs)
{
struct winlink *wl, *wl_loop;
log_debug("%s: window is @%u", __func__, fs->w->id);
wl = NULL;
if (fs->s->curw != NULL && fs->s->curw->window == fs->w)
wl = fs->s->curw;
@@ -244,146 +251,6 @@ cmd_find_best_winlink_with_window(struct cmd_find_state *fs)
return (0);
}
/* Find current session when we have an unattached client. */
static int
cmd_find_current_session_with_client(struct cmd_find_state *fs)
{
struct window_pane *wp;
/*
* If this is running in a pane, we can use that to limit the list of
* sessions to those containing that pane (we still use the current
* window in the best session).
*/
if (fs->item != NULL) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
if (strcmp(wp->tty, fs->item->client->ttyname) == 0)
break;
}
} else
wp = NULL;
/* Not running in a pane. We know nothing. Find the best session. */
if (wp == NULL)
goto unknown_pane;
/* Find the best session and winlink containing this pane. */
fs->w = wp->window;
if (cmd_find_best_session_with_window(fs) != 0) {
if (wp != NULL) {
/*
* The window may have been destroyed but the pane
* still on all_window_panes due to something else
* holding a reference.
*/
goto unknown_pane;
}
return (-1);
}
/* Use the current window and pane from this session. */
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
return (0);
unknown_pane:
fs->s = NULL;
if (fs->item != NULL)
fs->s = cmd_find_try_TMUX(fs->item->client, NULL);
if (fs->s == NULL)
fs->s = cmd_find_best_session(NULL, 0, fs->flags);
if (fs->s == NULL)
return (-1);
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
return (0);
}
/*
* Work out the best current state. If this function succeeds, the state is
* guaranteed to be completely filled in.
*/
static int
cmd_find_current_session(struct cmd_find_state *fs)
{
/* If we know the current client, use it. */
if (fs->item != NULL && fs->item->client != NULL) {
log_debug("%s: have client %p%s", __func__, fs->item->client,
fs->item->client->session == NULL ? "" : " (with session)");
if (fs->item->client->session == NULL)
return (cmd_find_current_session_with_client(fs));
fs->s = fs->item->client->session;
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
return (0);
}
/* We know nothing, find the best session and client. */
fs->s = cmd_find_best_session(NULL, 0, fs->flags);
if (fs->s == NULL)
return (-1);
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
return (0);
}
/* Work out the best current client. */
static struct client *
cmd_find_current_client(struct cmdq_item *item)
{
struct cmd_find_state current;
struct session *s;
struct client *c, **clist = NULL;
u_int csize;
/* If the queue client has a session, use it. */
if (item->client != NULL && item->client->session != NULL) {
log_debug("%s: using item %p client %p", __func__, item,
item->client);
return (item->client);
}
/* Otherwise find the current session. */
cmd_find_clear_state(&current, item, 0);
if (cmd_find_current_session(&current) != 0)
return (NULL);
/* If it is attached, find the best of it's clients. */
s = current.s;
log_debug("%s: current session $%u %s", __func__, s->id, s->name);
if (~s->flags & SESSION_UNATTACHED) {
csize = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != s)
continue;
clist = xreallocarray(clist, csize + 1, sizeof *clist);
clist[csize++] = c;
}
if (csize != 0) {
c = cmd_find_best_client(clist, csize);
if (c != NULL) {
free(clist);
return (c);
}
}
free(clist);
}
/* Otherwise pick best of all clients. */
return (cmd_find_best_client(NULL, 0));
}
/* Maps string in table. */
static const char *
cmd_find_map_table(const char *table[][2], const char *s)
@@ -537,7 +404,7 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window)
return (-1);
fs->idx = s->curw->idx + n;
} else {
if (n < s->curw->idx)
if (n > s->curw->idx)
return (-1);
fs->idx = s->curw->idx - n;
}
@@ -584,15 +451,16 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window)
if (window[0] != '+' && window[0] != '-') {
idx = strtonum(window, 0, INT_MAX, &errstr);
if (errstr == NULL) {
if (fs->flags & CMD_FIND_WINDOW_INDEX) {
fs->idx = idx;
return (0);
}
fs->wl = winlink_find_by_index(&fs->s->windows, idx);
if (fs->wl != NULL) {
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
return (0);
}
if (fs->flags & CMD_FIND_WINDOW_INDEX) {
fs->idx = idx;
return (0);
}
}
}
@@ -657,7 +525,7 @@ cmd_find_get_pane(struct cmd_find_state *fs, const char *pane, int only)
/* Check for pane ids starting with %. */
if (*pane == '%') {
fs->wp = window_pane_find_by_id_str(pane);
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
fs->w = fs->wp->window;
return (cmd_find_best_session_with_window(fs));
@@ -694,7 +562,7 @@ cmd_find_get_pane_with_session(struct cmd_find_state *fs, const char *pane)
/* Check for pane ids starting with %. */
if (*pane == '%') {
fs->wp = window_pane_find_by_id_str(pane);
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
fs->w = fs->wp->window;
return (cmd_find_best_winlink_with_window(fs));
@@ -726,7 +594,7 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
/* Check for pane ids starting with %. */
if (*pane == '%') {
fs->wp = window_pane_find_by_id_str(pane);
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
if (fs->wp->window != fs->w)
return (-1);
@@ -735,30 +603,28 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
/* Try special characters. */
if (strcmp(pane, "!") == 0) {
if (fs->w->last == NULL)
return (-1);
fs->wp = fs->w->last;
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
return (0);
} else if (strcmp(pane, "{up-of}") == 0) {
fs->wp = window_pane_find_up(fs->w->active);
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
return (0);
} else if (strcmp(pane, "{down-of}") == 0) {
fs->wp = window_pane_find_down(fs->w->active);
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
return (0);
} else if (strcmp(pane, "{left-of}") == 0) {
fs->wp = window_pane_find_left(fs->w->active);
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
return (0);
} else if (strcmp(pane, "{right-of}") == 0) {
fs->wp = window_pane_find_right(fs->w->active);
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
return (0);
}
@@ -774,7 +640,7 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
fs->wp = window_pane_next_by_number(fs->w, wp, n);
else
fs->wp = window_pane_previous_by_number(fs->w, wp, n);
if (fs->wp != NULL && !window_pane_outside(fs->wp))
if (fs->wp != NULL)
return (0);
}
@@ -782,13 +648,13 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
idx = strtonum(pane, 0, INT_MAX, &errstr);
if (errstr == NULL) {
fs->wp = window_pane_at_index(fs->w, idx);
if (fs->wp != NULL && !window_pane_outside(fs->wp))
if (fs->wp != NULL)
return (0);
}
/* Try as a description. */
fs->wp = window_find_string(fs->w, pane);
if (fs->wp != NULL && !window_pane_outside(fs->wp))
if (fs->wp != NULL)
return (0);
return (-1);
@@ -796,18 +662,16 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
/* Clear state. */
void
cmd_find_clear_state(struct cmd_find_state *fs, struct cmdq_item *item,
int flags)
cmd_find_clear_state(struct cmd_find_state *fs, int flags)
{
memset(fs, 0, sizeof *fs);
fs->item = item;
fs->flags = flags;
fs->idx = -1;
}
/* Check if state is empty/ */
/* Check if state is empty. */
int
cmd_find_empty_state(struct cmd_find_state *fs)
{
@@ -838,9 +702,7 @@ cmd_find_valid_state(struct cmd_find_state *fs)
if (fs->w != fs->wl->window)
return (0);
if (!window_has_pane(fs->w, fs->wp))
return (0);
return (!window_pane_outside(fs->wp));
return (window_has_pane(fs->w, fs->wp));
}
/* Copy a state. */
@@ -855,11 +717,11 @@ cmd_find_copy_state(struct cmd_find_state *dst, struct cmd_find_state *src)
}
/* Log the result. */
void
static void
cmd_find_log_state(const char *prefix, struct cmd_find_state *fs)
{
if (fs->s != NULL)
log_debug("%s: s=$%u", prefix, fs->s->id);
log_debug("%s: s=$%u %s", prefix, fs->s->id, fs->s->name);
else
log_debug("%s: s=none", prefix);
if (fs->wl != NULL) {
@@ -878,10 +740,10 @@ cmd_find_log_state(const char *prefix, struct cmd_find_state *fs)
}
/* Find state from a session. */
int
cmd_find_from_session(struct cmd_find_state *fs, struct session *s)
void
cmd_find_from_session(struct cmd_find_state *fs, struct session *s, int flags)
{
cmd_find_clear_state(fs, NULL, 0);
cmd_find_clear_state(fs, flags);
fs->s = s;
fs->wl = fs->s->curw;
@@ -889,36 +751,35 @@ cmd_find_from_session(struct cmd_find_state *fs, struct session *s)
fs->wp = fs->w->active;
cmd_find_log_state(__func__, fs);
return (0);
}
/* Find state from a winlink. */
int
cmd_find_from_winlink(struct cmd_find_state *fs, struct session *s,
struct winlink *wl)
void
cmd_find_from_winlink(struct cmd_find_state *fs, struct winlink *wl, int flags)
{
cmd_find_clear_state(fs, NULL, 0);
cmd_find_clear_state(fs, flags);
fs->s = s;
fs->s = wl->session;
fs->wl = wl;
fs->w = wl->window;
fs->wp = wl->window->active;
cmd_find_log_state(__func__, fs);
return (0);
}
/* Find state from a session and window. */
int
cmd_find_from_session_window(struct cmd_find_state *fs, struct session *s,
struct window *w)
struct window *w, int flags)
{
cmd_find_clear_state(fs, NULL, 0);
cmd_find_clear_state(fs, flags);
fs->s = s;
fs->w = w;
if (cmd_find_best_winlink_with_window(fs) != 0)
if (cmd_find_best_winlink_with_window(fs) != 0) {
cmd_find_clear_state(fs, flags);
return (-1);
}
fs->wp = fs->w->active;
cmd_find_log_state(__func__, fs);
@@ -927,28 +788,46 @@ cmd_find_from_session_window(struct cmd_find_state *fs, struct session *s,
/* Find state from a window. */
int
cmd_find_from_window(struct cmd_find_state *fs, struct window *w)
cmd_find_from_window(struct cmd_find_state *fs, struct window *w, int flags)
{
cmd_find_clear_state(fs, NULL, 0);
cmd_find_clear_state(fs, flags);
fs->w = w;
if (cmd_find_best_session_with_window(fs) != 0)
if (cmd_find_best_session_with_window(fs) != 0) {
cmd_find_clear_state(fs, flags);
return (-1);
if (cmd_find_best_winlink_with_window(fs) != 0)
}
if (cmd_find_best_winlink_with_window(fs) != 0) {
cmd_find_clear_state(fs, flags);
return (-1);
}
fs->wp = fs->w->active;
cmd_find_log_state(__func__, fs);
return (0);
}
/* Find state from a winlink and pane. */
void
cmd_find_from_winlink_pane(struct cmd_find_state *fs, struct winlink *wl,
struct window_pane *wp, int flags)
{
cmd_find_clear_state(fs, flags);
fs->s = wl->session;
fs->wl = wl;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = wp;
cmd_find_log_state(__func__, fs);
}
/* Find state from a pane. */
int
cmd_find_from_pane(struct cmd_find_state *fs, struct window_pane *wp)
cmd_find_from_pane(struct cmd_find_state *fs, struct window_pane *wp, int flags)
{
if (cmd_find_from_window(fs, wp->window) != 0)
return (-1);
if (window_pane_outside(wp))
if (cmd_find_from_window(fs, wp->window, flags) != 0)
return (-1);
fs->wp = wp;
@@ -956,56 +835,198 @@ cmd_find_from_pane(struct cmd_find_state *fs, struct window_pane *wp)
return (0);
}
/* Find current state. */
/* Find state from nothing. */
int
cmd_find_current(struct cmd_find_state *fs, struct cmdq_item *item, int flags)
cmd_find_from_nothing(struct cmd_find_state *fs, int flags)
{
cmd_find_clear_state(fs, item, flags);
if (cmd_find_current_session(fs) != 0) {
if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "no current session");
cmd_find_clear_state(fs, flags);
fs->s = cmd_find_best_session(NULL, 0, flags);
if (fs->s == NULL) {
cmd_find_clear_state(fs, flags);
return (-1);
}
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
cmd_find_log_state(__func__, fs);
return (0);
}
/* Find state from mouse. */
int
cmd_find_from_mouse(struct cmd_find_state *fs, struct mouse_event *m, int flags)
{
cmd_find_clear_state(fs, flags);
if (!m->valid)
return (-1);
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
if (fs->wp == NULL) {
cmd_find_clear_state(fs, flags);
return (-1);
}
fs->w = fs->wl->window;
cmd_find_log_state(__func__, fs);
return (0);
}
/* Find state from client. */
int
cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
{
struct session *s;
struct winlink *wl;
struct window_pane *wp;
/* If no client, treat as from nothing. */
if (c == NULL)
return (cmd_find_from_nothing(fs, flags));
/* If this is an attached client, all done. */
if (c->session != NULL) {
cmd_find_from_session(fs, c->session, flags);
return (0);
}
cmd_find_clear_state(fs, flags);
/*
* If this is an unattached client running in a pane, we can use that
* to limit the list of sessions to those containing that pane.
*/
wp = cmd_find_inside_pane(c);
if (wp == NULL)
goto unknown_pane;
/* If we have a session in TMUX, see if it has this pane. */
s = cmd_find_try_TMUX(c);
if (s != NULL) {
RB_FOREACH(wl, winlinks, &s->windows) {
if (window_has_pane(wl->window, wp))
break;
}
if (wl != NULL) {
log_debug("%s: session $%u has pane %%%u", __func__,
s->id, wp->id);
fs->s = s;
fs->wl = s->curw; /* use current session */
fs->w = fs->wl->window;
fs->wp = fs->w->active; /* use active pane */
cmd_find_log_state(__func__, fs);
return (0);
} else {
log_debug("%s: session $%u does not have pane %%%u",
__func__, s->id, wp->id);
}
}
/*
* Don't have a session, or it doesn't have this pane. Try all
* sessions.
*/
fs->w = wp->window;
if (cmd_find_best_session_with_window(fs) != 0) {
/*
* The window may have been destroyed but the pane
* still on all_window_panes due to something else
* holding a reference.
*/
goto unknown_pane;
}
fs->wl = fs->s->curw;
fs->w = fs->wl->window;
fs->wp = fs->w->active; /* use active pane */
cmd_find_log_state(__func__, fs);
return (0);
unknown_pane:
/*
* We're not running in a known pane, but maybe this client has TMUX
* in the environment. That'd give us a session.
*/
s = cmd_find_try_TMUX(c);
if (s != NULL) {
cmd_find_from_session(fs, s, flags);
return (0);
}
/* Otherwise we need to guess. */
return (cmd_find_from_nothing(fs, flags));
}
/*
* Split target into pieces and resolve for the given type. Fills in the given
* state. Returns 0 on success or -1 on error.
*/
int
cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
struct cmdq_item *item, const char *target, enum cmd_find_type type,
int flags)
cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
const char *target, enum cmd_find_type type, int flags)
{
struct mouse_event *m;
char *colon, *period, *copy = NULL;
const char *session, *window, *pane;
struct cmd_find_state current;
char *colon, *period, *copy = NULL, tmp[256];
const char *session, *window, *pane, *s;
int window_only = 0, pane_only = 0;
/* Can fail flag implies quiet. */
if (flags & CMD_FIND_CANFAIL)
flags |= CMD_FIND_QUIET;
/* Log the arguments. */
if (target == NULL)
log_debug("%s: target none, type %d", __func__, type);
if (type == CMD_FIND_PANE)
s = "pane";
else if (type == CMD_FIND_WINDOW)
s = "window";
else if (type == CMD_FIND_SESSION)
s = "session";
else
log_debug("%s: target %s, type %d", __func__, target, type);
log_debug("%s: item %p, flags %#x", __func__, item, flags);
s = "unknown";
*tmp = '\0';
if (flags & CMD_FIND_PREFER_UNATTACHED)
strlcat(tmp, "PREFER_UNATTACHED,", sizeof tmp);
if (flags & CMD_FIND_QUIET)
strlcat(tmp, "QUIET,", sizeof tmp);
if (flags & CMD_FIND_WINDOW_INDEX)
strlcat(tmp, "WINDOW_INDEX,", sizeof tmp);
if (flags & CMD_FIND_DEFAULT_MARKED)
strlcat(tmp, "DEFAULT_MARKED,", sizeof tmp);
if (flags & CMD_FIND_EXACT_SESSION)
strlcat(tmp, "EXACT_SESSION,", sizeof tmp);
if (flags & CMD_FIND_EXACT_WINDOW)
strlcat(tmp, "EXACT_WINDOW,", sizeof tmp);
if (flags & CMD_FIND_CANFAIL)
strlcat(tmp, "CANFAIL,", sizeof tmp);
if (*tmp != '\0')
tmp[strlen(tmp) - 1] = '\0';
log_debug("%s: target %s, type %s, item %p, flags %s", __func__,
target == NULL ? "none" : target, s, item, tmp);
/* Clear new state. */
cmd_find_clear_state(fs, item, flags);
cmd_find_clear_state(fs, flags);
/* Find current state. */
if (server_check_marked() && (flags & CMD_FIND_DEFAULT_MARKED)) {
fs->current = &marked_pane;
log_debug("%s: current is marked pane", __func__);
} else if (cmd_find_valid_state(&item->current)) {
fs->current = &item->current;
} else if (cmd_find_valid_state(&item->shared->current)) {
fs->current = &item->shared->current;
log_debug("%s: current is from queue", __func__);
} else if (cmd_find_from_client(&current, item->client, flags) == 0) {
fs->current = &current;
log_debug("%s: current is from client", __func__);
} else {
fs->current = current;
log_debug("%s: current is from argument", __func__);
if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "no current target");
goto error;
}
if (!cmd_find_empty_state(fs->current) &&
!cmd_find_valid_state(fs->current))
if (!cmd_find_valid_state(fs->current))
fatalx("invalid current find state");
/* An empty or NULL target is the current. */
@@ -1014,11 +1035,11 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
/* Mouse target is a plain = or {mouse}. */
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
m = &item->mouse;
m = &item->shared->mouse;
switch (type) {
case CMD_FIND_PANE:
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
if (fs->wp != NULL && !window_pane_outside(fs->wp))
if (fs->wp != NULL)
fs->w = fs->wl->window;
break;
case CMD_FIND_WINDOW:
@@ -1125,9 +1146,16 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
if (pane != NULL)
pane = cmd_find_map_table(cmd_find_pane_table, pane);
log_debug("target %s (flags %#x): session=%s, window=%s, pane=%s",
target, flags, session == NULL ? "none" : session,
window == NULL ? "none" : window, pane == NULL ? "none" : pane);
if (session != NULL || window != NULL || pane != NULL) {
log_debug("%s: target %s is %s%s%s%s%s%s",
__func__, target,
session == NULL ? "" : "session ",
session == NULL ? "" : session,
window == NULL ? "" : "window ",
window == NULL ? "" : window,
pane == NULL ? "" : "pane ",
pane == NULL ? "" : pane);
}
/* No pane is allowed if want an index. */
if (pane != NULL && (flags & CMD_FIND_WINDOW_INDEX)) {
@@ -1156,7 +1184,8 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
/* This will fill in winlink and window. */
if (cmd_find_get_window_with_session(fs, window) != 0)
goto no_window;
fs->wp = fs->wl->window->active;
if (fs->wl != NULL) /* can be NULL if index only */
fs->wp = fs->wl->window->active;
goto found;
}
@@ -1196,7 +1225,8 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
/* This will fill in session, winlink and window. */
if (cmd_find_get_window(fs, window, window_only) != 0)
goto no_window;
fs->wp = fs->wl->window->active;
if (fs->wl != NULL) /* can be NULL if index only */
fs->wp = fs->wl->window->active;
goto found;
}
@@ -1220,6 +1250,8 @@ error:
log_debug("%s: error", __func__);
free(copy);
if (flags & CMD_FIND_CANFAIL)
return (0);
return (-1);
found:
@@ -1231,20 +1263,49 @@ found:
no_session:
if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "can't find session %s", session);
cmdq_error(item, "can't find session: %s", session);
goto error;
no_window:
if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "can't find window %s", window);
cmdq_error(item, "can't find window: %s", window);
goto error;
no_pane:
if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "can't find pane %s", pane);
cmdq_error(item, "can't find pane: %s", pane);
goto error;
}
/* Find the current client. */
static struct client *
cmd_find_current_client(struct cmdq_item *item, int quiet)
{
struct client *c;
struct session *s;
struct window_pane *wp;
struct cmd_find_state fs;
if (item->client != NULL && item->client->session != NULL)
return (item->client);
c = NULL;
if ((wp = cmd_find_inside_pane(item->client)) != NULL) {
cmd_find_clear_state(&fs, CMD_FIND_QUIET);
fs.w = wp->window;
if (cmd_find_best_session_with_window(&fs) == 0)
c = cmd_find_best_client(fs.s);
} else {
s = cmd_find_best_session(NULL, 0, CMD_FIND_QUIET);
if (s != NULL)
c = cmd_find_best_client(s);
}
if (c == NULL && !quiet)
cmdq_error(item, "no current client");
log_debug("%s: no target, return %p", __func__, c);
return (c);
}
/* Find the target client or report an error and return NULL. */
struct client *
cmd_find_client(struct cmdq_item *item, const char *target, int quiet)
@@ -1254,13 +1315,8 @@ cmd_find_client(struct cmdq_item *item, const char *target, int quiet)
size_t size;
/* A NULL argument means the current client. */
if (item != NULL && target == NULL) {
c = cmd_find_current_client(item);
if (c == NULL && !quiet)
cmdq_error(item, "no current client");
log_debug("%s: no target, return %p", __func__, c);
return (c);
}
if (target == NULL)
return (cmd_find_current_client(item, quiet));
copy = xstrdup(target);
/* Trim a single trailing colon if any. */
@@ -1287,7 +1343,7 @@ cmd_find_client(struct cmdq_item *item, const char *target, int quiet)
/* If no client found, report an error. */
if (c == NULL && !quiet)
cmdq_error(item, "can't find client %s", copy);
cmdq_error(item, "can't find client: %s", copy);
free(copy);
log_debug("%s: target %s, return %p", __func__, target, c);

View File

@@ -31,7 +31,6 @@
static enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmdq_item *);
static enum cmd_retval cmd_if_shell_error(struct cmdq_item *, void *);
static void cmd_if_shell_callback(struct job *);
static void cmd_if_shell_free(void *);
@@ -43,7 +42,7 @@ const struct cmd_entry cmd_if_shell_entry = {
.usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command "
"[command]",
.tflag = CMD_PANE_CANFAIL,
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = 0,
.exec = cmd_if_shell_exec
@@ -65,22 +64,15 @@ static enum cmd_retval
cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmdq_shared *shared = item->shared;
struct cmd_if_shell_data *cdata;
char *shellcmd, *cmd, *cause;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
struct client *c = item->state.c;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct window_pane *wp = item->state.tflag.wp;
const char *cwd;
if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
else if (s != NULL)
cwd = s->cwd;
else
cwd = NULL;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
shellcmd = format_single(item, args->argv[0], c, s, wl, wp);
if (args_has(args, 'F')) {
@@ -100,7 +92,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
}
return (CMD_RETURN_ERROR);
}
new_item = cmdq_get_command(cmdlist, NULL, &item->mouse, 0);
new_item = cmdq_get_command(cmdlist, NULL, &shared->mouse, 0);
cmdq_insert_after(item, new_item);
cmd_list_free(cmdlist);
return (CMD_RETURN_NORMAL);
@@ -119,16 +111,22 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->cmd_else = NULL;
cdata->client = item->client;
cdata->client->references++;
if (cdata->client != NULL)
cdata->client->references++;
if (!args_has(args, 'b'))
cdata->item = item;
else
cdata->item = NULL;
memcpy(&cdata->mouse, &item->mouse, sizeof cdata->mouse);
memcpy(&cdata->mouse, &shared->mouse, sizeof cdata->mouse);
job_run(shellcmd, s, cwd, cmd_if_shell_callback, cmd_if_shell_free,
cdata);
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);
if (args_has(args, 'b'))
@@ -136,28 +134,19 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_WAIT);
}
static enum cmd_retval
cmd_if_shell_error(struct cmdq_item *item, void *data)
{
char *error = data;
cmdq_error(item, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static void
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 client *c = cdata->client;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
char *cause, *cmd, *file = cdata->file;
u_int line = cdata->line;
int status;
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
status = job_get_status(job);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
cmd = cdata->cmd_else;
else
cmd = cdata->cmd_if;
@@ -166,10 +155,10 @@ cmd_if_shell_callback(struct job *job)
cmdlist = cmd_string_parse(cmd, file, line, &cause);
if (cmdlist == NULL) {
if (cause != NULL)
new_item = cmdq_get_callback(cmd_if_shell_error, cause);
else
new_item = NULL;
if (cause != NULL && cdata->item != NULL)
cmdq_error(cdata->item, "%s", cause);
free(cause);
new_item = NULL;
} else {
new_item = cmdq_get_command(cmdlist, NULL, &cdata->mouse, 0);
cmd_list_free(cmdlist);
@@ -192,7 +181,8 @@ cmd_if_shell_free(void *data)
{
struct cmd_if_shell_data *cdata = data;
server_client_unref(cdata->client);
if (cdata->client != NULL)
server_client_unref(cdata->client);
free(cdata->cmd_else);
free(cdata->cmd_if);

View File

@@ -37,8 +37,8 @@ const struct cmd_entry cmd_join_pane_entry = {
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.sflag = CMD_PANE_MARKED,
.tflag = CMD_PANE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_join_pane_exec
@@ -51,8 +51,8 @@ const struct cmd_entry cmd_move_pane_entry = {
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.sflag = CMD_PANE,
.tflag = CMD_PANE,
.source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_join_pane_exec
@@ -62,6 +62,7 @@ static enum cmd_retval
cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct session *dst_s;
struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w;
@@ -77,15 +78,15 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
else
not_same_window = 0;
dst_s = item->state.tflag.s;
dst_wl = item->state.tflag.wl;
dst_wp = item->state.tflag.wp;
dst_s = item->target.s;
dst_wl = item->target.wl;
dst_wp = item->target.wp;
dst_w = dst_wl->window;
dst_idx = dst_wl->idx;
server_unzoom_window(dst_w);
src_wl = item->state.sflag.wl;
src_wp = item->state.sflag.wp;
src_wl = item->source.wl;
src_wp = item->source.wp;
src_w = src_wl->window;
server_unzoom_window(src_w);
@@ -145,6 +146,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'd')) {
window_set_active_pane(dst_w, src_wp);
session_select(dst_s, dst_idx);
cmd_find_from_session(current, dst_s, 0);
server_redraw_session(dst_s);
} else
server_status_session(dst_s);

View File

@@ -35,7 +35,7 @@ const struct cmd_entry cmd_kill_pane_entry = {
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_kill_pane_exec
@@ -44,12 +44,11 @@ const struct cmd_entry cmd_kill_pane_entry = {
static enum cmd_retval
cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct winlink *wl = item->state.tflag.wl;
struct window_pane *loopwp, *tmpwp, *wp = item->state.tflag.wp;
server_unzoom_window(wl->window);
struct winlink *wl = item->target.wl;
struct window_pane *loopwp, *tmpwp, *wp = item->target.wp;
if (args_has(self->args, 'a')) {
server_unzoom_window(wl->window);
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
if (loopwp == wp)
continue;
@@ -60,13 +59,6 @@ cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
if (window_count_panes(wl->window) == 1) {
server_kill_window(wl->window);
recalculate_sizes();
} else {
layout_close_pane(wp);
window_remove_pane(wl->window, wp);
server_redraw_window(wl->window);
}
server_kill_pane(wp);
return (CMD_RETURN_NORMAL);
}

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_kill_session_entry = {
.args = { "aCt:", 0, 0 },
.usage = "[-aC] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_kill_session_exec
@@ -49,7 +49,7 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
struct session *s, *sloop, *stmp;
struct winlink *wl;
s = item->state.tflag.s;
s = item->target.s;
if (args_has(args, 'C')) {
RB_FOREACH(wl, winlinks, &s->windows) {
@@ -61,12 +61,12 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) {
if (sloop != s) {
server_destroy_session(sloop);
session_destroy(sloop);
session_destroy(sloop, __func__);
}
}
} else {
server_destroy_session(s);
session_destroy(s);
session_destroy(s, __func__);
}
return (CMD_RETURN_NORMAL);
}

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_kill_window_entry = {
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_kill_window_exec
@@ -46,7 +46,7 @@ const struct cmd_entry cmd_unlink_window_entry = {
.args = { "kt:", 0, 0 },
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_kill_window_exec
@@ -56,9 +56,9 @@ static enum cmd_retval
cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl, *wl2, *wl3;
struct winlink *wl = item->target.wl, *wl2, *wl3;
struct window *w = wl->window;
struct session *s = item->state.tflag.s;
struct session *s = item->target.s;
if (self->entry == &cmd_unlink_window_entry) {
if (!args_has(self->args, 'k') && !session_is_linked(s, w)) {

View File

@@ -57,7 +57,7 @@ cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item)
pb = NULL;
while ((pb = paste_walk(pb)) != NULL) {
ft = format_create(item, FORMAT_NONE, 0);
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults_paste_buffer(ft, pb);
line = format_expand(ft, template);

View File

@@ -42,7 +42,7 @@ const struct cmd_entry cmd_list_clients_entry = {
.args = { "F:t:", 0, 0 },
.usage = "[-F format] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_READONLY|CMD_AFTERHOOK,
.exec = cmd_list_clients_exec
@@ -60,7 +60,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
char *line;
if (args_has(args, 't'))
s = item->state.tflag.s;
s = item->target.s;
else
s = NULL;
@@ -72,7 +72,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
if (c->session == NULL || (s != NULL && s != c->session))
continue;
ft = format_create(item, FORMAT_NONE, 0);
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", idx);
format_defaults(ft, c, NULL, NULL, NULL);

View File

@@ -75,13 +75,17 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
repeat = 0;
tablewidth = keywidth = 0;
RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
table = key_bindings_first_table ();
while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table);
continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
}
bd = key_bindings_first(table);
while (bd != NULL) {
key = key_string_lookup_key(bd->key);
if (bd->can_repeat)
if (bd->flags & KEY_BINDING_REPEAT)
repeat = 1;
width = utf8_cstrwidth(table->name);
@@ -90,18 +94,25 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
width = utf8_cstrwidth(key);
if (width > keywidth)
keywidth = width;
bd = key_bindings_next(table, bd);
}
table = key_bindings_next_table(table);
}
RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
table = key_bindings_first_table ();
while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table);
continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
}
bd = key_bindings_first(table);
while (bd != NULL) {
key = key_string_lookup_key(bd->key);
if (!repeat)
r = "";
else if (bd->can_repeat)
else if (bd->flags & KEY_BINDING_REPEAT)
r = "-r ";
else
r = " ";
@@ -122,7 +133,9 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
free(cp);
cmdq_print(item, "bind-key %s", tmp);
bd = key_bindings_next(table, bd);
}
table = key_bindings_next_table(table);
}
return (CMD_RETURN_NORMAL);
@@ -144,7 +157,7 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
"#{command_list_usage}";
}
ft = format_create(item, FORMAT_NONE, 0);
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, NULL, NULL, NULL, NULL);
for (entryp = cmd_table; *entryp != NULL; entryp++) {

View File

@@ -41,7 +41,7 @@ const struct cmd_entry cmd_list_panes_entry = {
.args = { "asF:t:", 0, 0 },
.usage = "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_list_panes_exec
@@ -51,8 +51,8 @@ static enum cmd_retval
cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
if (args_has(args, 'a'))
cmd_list_panes_server(self, item);
@@ -123,7 +123,7 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
n = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
ft = format_create(item, FORMAT_NONE, 0);
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, wp);

View File

@@ -30,8 +30,7 @@
#define LIST_SESSIONS_TEMPLATE \
"#{session_name}: #{session_windows} windows " \
"(created #{t:session_created}) " \
"[#{session_width}x#{session_height}]" \
"(created #{t:session_created})" \
"#{?session_grouped, (group ,}" \
"#{session_group}#{?session_grouped,),}" \
"#{?session_attached, (attached),}"
@@ -65,7 +64,7 @@ cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
n = 0;
RB_FOREACH(s, sessions, &sessions) {
ft = format_create(item, FORMAT_NONE, 0);
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, NULL, NULL);

View File

@@ -52,7 +52,7 @@ const struct cmd_entry cmd_list_windows_entry = {
.args = { "F:at:", 0, 0 },
.usage = "[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_list_windows_exec
@@ -66,7 +66,7 @@ cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'a'))
cmd_list_windows_server(self, item);
else
cmd_list_windows_session(self, item->state.tflag.s, item, 0);
cmd_list_windows_session(self, item->target.s, item, 0);
return (CMD_RETURN_NORMAL);
}
@@ -86,7 +86,7 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
{
struct args *args = self->args;
struct winlink *wl;
u_int n;
u_int n;
struct format_tree *ft;
const char *template;
char *line;
@@ -105,7 +105,7 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
n = 0;
RB_FOREACH(wl, winlinks, &s->windows) {
ft = format_create(item, FORMAT_NONE, 0);
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, NULL);

View File

@@ -56,10 +56,14 @@ cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_load_buffer_data *cdata;
struct client *c = item->client;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
FILE *f;
const char *path, *bufname;
char *pdata, *new_pdata, *cause, *file;
const char *bufname;
char *pdata = NULL, *new_pdata, *cause;
char *path, *file;
size_t psize;
int ch, error;
@@ -67,8 +71,11 @@ cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(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) {
free(path);
c = item->client;
cdata = xcalloc(1, sizeof *cdata);
cdata->item = item;
@@ -78,19 +85,21 @@ cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
error = server_set_stdin_callback(c, cmd_load_buffer_callback,
cdata, &cause);
if (error != 0) {
cmdq_error(item, "%s: %s", path, cause);
cmdq_error(item, "-: %s", cause);
free(cause);
free(cdata);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_WAIT);
}
file = server_client_get_path(c, path);
free(path);
f = fopen(file, "rb");
if (f == NULL) {
cmdq_error(item, "%s: %s", file, strerror(errno));
free(file);
return (CMD_RETURN_ERROR);
goto error;
}
pdata = NULL;
@@ -127,6 +136,7 @@ error:
free(pdata);
if (f != NULL)
fclose(f);
free(file);
return (CMD_RETURN_ERROR);
}

View File

@@ -44,7 +44,7 @@ const struct cmd_entry cmd_lock_session_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec
@@ -57,22 +57,25 @@ const struct cmd_entry cmd_lock_client_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec
};
static enum cmd_retval
cmd_lock_server_exec(struct cmd *self, __unused struct cmdq_item *item)
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)
server_lock();
else if (self->entry == &cmd_lock_session_entry)
server_lock_session(item->state.tflag.s);
else
server_lock_client(item->state.c);
server_lock_session(item->target.s);
else {
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
server_lock_client(c);
}
recalculate_sizes();
return (CMD_RETURN_NORMAL);

View File

@@ -35,8 +35,8 @@ const struct cmd_entry cmd_move_window_entry = {
.args = { "adkrs:t:", 0, 0 },
.usage = "[-dkr] " CMD_SRCDST_WINDOW_USAGE,
.sflag = CMD_WINDOW,
.tflag = CMD_MOVEW_R,
.source = { 's', CMD_FIND_WINDOW, 0 },
/* -t is special */
.flags = 0,
.exec = cmd_move_window_exec
@@ -49,8 +49,8 @@ const struct cmd_entry cmd_link_window_entry = {
.args = { "adks:t:", 0, 0 },
.usage = "[-dk] " CMD_SRCDST_WINDOW_USAGE,
.sflag = CMD_WINDOW,
.tflag = CMD_WINDOW_INDEX,
.source = { 's', CMD_FIND_WINDOW, 0 },
/* -t is special */
.flags = 0,
.exec = cmd_move_window_exec
@@ -60,18 +60,31 @@ static enum cmd_retval
cmd_move_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct session *src = item->state.sflag.s;
struct session *dst = item->state.tflag.s;
struct winlink *wl = item->state.sflag.wl;
const char *tflag = args_get(args, 't');
struct session *src;
struct session *dst;
struct winlink *wl;
char *cause;
int idx = item->state.tflag.idx, kflag, dflag, sflag;
int idx, kflag, dflag, sflag;
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();
server_status_session(item->target.s);
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');
dflag = args_has(self->args, 'd');

View File

@@ -44,7 +44,7 @@ const struct cmd_entry cmd_new_session_entry = {
"[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
"[-y height] [command]",
.tflag = CMD_SESSION_CANFAIL,
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_STARTSERVER,
.exec = cmd_new_session_exec
@@ -57,7 +57,7 @@ const struct cmd_entry cmd_has_session_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_new_session_exec
@@ -71,20 +71,23 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
struct session *s, *as, *groupwith;
struct window *w;
struct environ *env;
struct options *oo;
struct termios tio, *tiop;
struct session_group *sg;
const char *newname, *errstr, *template, *group, *prefix;
const char *path, *cmd, *cwd, *to_free = NULL;
char **argv, *cause, *cp;
const char *errstr, *template, *group, *prefix;
const char *path, *cmd, *tmp, *value;
char **argv, *cause, *cp, *newname, *cwd = NULL;
int detached, already_attached, idx, argc;
u_int sx, sy;
int is_control = 0;
u_int sx, sy, dsx = 80, dsy = 24;
struct environ_entry *envent;
struct cmd_find_state fs;
enum cmd_retval retval;
if (self->entry == &cmd_has_session_entry) {
/*
* cmd_prepare() will fail if the session cannot be found,
* hence always return success here.
* cmd_find_target() will fail if the session cannot be found,
* so always return success here.
*/
return (CMD_RETURN_NORMAL);
}
@@ -94,34 +97,31 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
newname = args_get(args, 's');
if (newname != NULL) {
newname = NULL;
if (args_has(args, 's')) {
newname = format_single(item, args_get(args, 's'), c, NULL,
NULL, NULL);
if (!session_check_name(newname)) {
cmdq_error(item, "bad session name: %s", newname);
return (CMD_RETURN_ERROR);
goto error;
}
if ((as = session_find(newname)) != NULL) {
if (args_has(args, 'A')) {
/*
* This item is now destined for
* attach-session. Because attach-session will
* have already been prepared, copy this
* session into its tflag so it can be used.
*/
cmd_find_from_session(&item->state.tflag, as);
return (cmd_attach_session(item,
args_has(args, 'D'), 0, NULL,
args_has(args, 'E')));
retval = cmd_attach_session(item,
newname, args_has(args, 'D'),
0, NULL, args_has(args, 'E'));
free(newname);
return (retval);
}
cmdq_error(item, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR);
goto error;
}
}
/* Is this going to be part of a session group? */
group = args_get(args, 't');
if (group != NULL) {
groupwith = item->state.tflag.s;
groupwith = item->target.s;
if (groupwith == NULL) {
if (!session_check_name(group)) {
cmdq_error(item, "bad group name: %s", group);
@@ -146,6 +146,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
detached = args_has(args, 'd');
if (c == NULL)
detached = 1;
else if (c->flags & CLIENT_CONTROL)
is_control = 1;
/* Is this client already attached? */
already_attached = 0;
@@ -153,13 +155,10 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
already_attached = 1;
/* Get the new session working directory. */
if (args_has(args, 'c')) {
cwd = args_get(args, 'c');
to_free = cwd = format_single(item, cwd, c, NULL, NULL, NULL);
} else if (c != NULL && c->session == NULL && c->cwd != NULL)
cwd = c->cwd;
if ((tmp = args_get(args, 'c')) != NULL)
cwd = format_single(item, tmp, c, NULL, NULL, NULL);
else
cwd = ".";
cwd = xstrdup(server_client_get_cwd(c, NULL));
/*
* If this is a new client, check for nesting and save the termios
@@ -191,30 +190,51 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
}
}
/* 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 = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
goto error;
}
}
}
if (args_has(args, 'y')) {
tmp = args_get(args, 'y');
if (strcmp(tmp, "-") == 0) {
if (c != NULL)
dsy = c->tty.sy;
} else {
dsy = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
goto error;
}
}
}
/* Find new session size. */
if (c != NULL) {
if (!detached && !is_control) {
sx = c->tty.sx;
sy = c->tty.sy;
if (sy > 0 && options_get_number(global_s_options, "status"))
sy--;
} else {
sx = 80;
sy = 24;
}
if (detached && args_has(args, 'x')) {
sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
goto error;
value = options_get_string(global_s_options, "default-size");
if (sscanf(value, "%ux%u", &sx, &sy) != 2) {
sx = 80;
sy = 24;
}
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(item, "height %s", errstr);
goto error;
}
}
if (sy > 0 && options_get_number(global_s_options, "status"))
sy--;
if (sx == 0)
sx = 1;
if (sy == 0)
@@ -250,10 +270,15 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (c != NULL && !args_has(args, 'E'))
environ_update(global_s_options, c->environ, env);
/* Set up the options. */
oo = options_create(global_s_options);
if (args_has(args, 'x') || args_has(args, 'y'))
options_set_string(oo, "default-size", 0, "%ux%u", dsx, dsy);
/* Create the new session. */
idx = -1 - options_get_number(global_s_options, "base-index");
s = session_create(prefix, newname, argc, argv, path, cwd, env, tiop,
idx, sx, sy, &cause);
s = session_create(prefix, newname, argc, argv, path, cwd, env, oo,
tiop, idx, &cause);
environ_free(env);
if (s == NULL) {
cmdq_error(item, "create session failed: %s", cause);
@@ -262,10 +287,12 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
}
/* Set the initial window name if one given. */
if (argc >= 0 && args_has(args, 'n')) {
if (argc >= 0 && (tmp = args_get(args, 'n')) != NULL) {
cp = format_single(item, tmp, c, s, NULL, NULL);
w = s->curw->window;
window_set_name(w, args_get(args, 'n'));
window_set_name(w, cp);
options_set_number(w->options, "automatic-rename", 0);
free(cp);
}
/*
@@ -297,8 +324,9 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
} else if (c->session != NULL)
c->last_session = c->session;
c->session = s;
if (!item->repeat)
if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
@@ -324,19 +352,20 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
free(cp);
}
if (!detached)
if (!detached) {
c->flags |= CLIENT_ATTACHED;
cmd_find_from_session(&item->shared->current, s, 0);
}
if (to_free != NULL)
free((void *)to_free);
cmd_find_from_session(&fs, s);
cmd_find_from_session(&fs, s, 0);
hooks_insert(s->hooks, item, &fs, "after-new-session");
free(cwd);
free(newname);
return (CMD_RETURN_NORMAL);
error:
if (to_free != NULL)
free((void *)to_free);
free(cwd);
free(newname);
return (CMD_RETURN_ERROR);
}

View File

@@ -42,7 +42,7 @@ const struct cmd_entry cmd_new_window_entry = {
.usage = "[-adkP] [-c start-directory] [-F format] [-n window-name] "
CMD_TARGET_WINDOW_USAGE " [command]",
.tflag = CMD_WINDOW_INDEX,
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
.flags = 0,
.exec = cmd_new_window_exec
@@ -52,17 +52,18 @@ static enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct client *c = item->state.c;
int idx = item->state.tflag.idx;
const char *cmd, *path, *template, *cwd, *to_free;
char **argv, *cause, *cp;
struct cmd_find_state *current = &item->shared->current;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct client *c = cmd_find_client(item, NULL, 1);
int idx = item->target.idx;
const char *cmd, *path, *template, *tmp;
char **argv, *cause, *cp, *cwd, *name;
int argc, detached;
struct environ_entry *envent;
struct cmd_find_state fs;
if (args_has(args, 'a')) {
if (args_has(args, 'a') && wl != NULL) {
if ((idx = winlink_shuffle_up(s, wl)) == -1) {
cmdq_error(item, "no free window indexes");
return (CMD_RETURN_ERROR);
@@ -92,16 +93,16 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if (envent != NULL)
path = envent->value;
to_free = NULL;
if (args_has(args, 'c')) {
cwd = args_get(args, 'c');
to_free = cwd = format_single(item, cwd, c, s, NULL, NULL);
} else if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
if ((tmp = args_get(args, 'c')) != NULL)
cwd = format_single(item, tmp, c, s, NULL, NULL);
else
cwd = s->cwd;
cwd = xstrdup(server_client_get_cwd(item->client, s));
if ((tmp = args_get(args, 'n')) != NULL)
name = format_single(item, tmp, c, s, NULL, NULL);
else
name = NULL;
wl = NULL;
if (idx != -1)
wl = winlink_find_by_index(&s->windows, idx);
if (wl != NULL && args_has(args, 'k')) {
@@ -123,7 +124,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if (idx == -1)
idx = -1 - options_get_number(s->options, "base-index");
wl = session_new(s, args_get(args, 'n'), argc, argv, path, cwd, idx,
wl = session_new(s, name, argc, argv, path, cwd, idx,
&cause);
if (wl == NULL) {
cmdq_error(item, "create window failed: %s", cause);
@@ -132,6 +133,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
}
if (!detached) {
session_select(s, wl->idx);
cmd_find_from_winlink(current, wl, 0);
server_redraw_session_group(s);
} else
server_status_session_group(s);
@@ -144,16 +146,15 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
free(cp);
}
if (to_free != NULL)
free((void *)to_free);
cmd_find_from_winlink(&fs, s, wl);
cmd_find_from_winlink(&fs, wl, 0);
hooks_insert(s->hooks, item, &fs, "after-new-window");
free(name);
free(cwd);
return (CMD_RETURN_NORMAL);
error:
if (to_free != NULL)
free((void *)to_free);
free(name);
free(cwd);
return (CMD_RETURN_ERROR);
}

View File

@@ -37,7 +37,7 @@ const struct cmd_entry cmd_paste_buffer_entry = {
.usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " "
CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_paste_buffer_exec
@@ -47,7 +47,7 @@ static enum cmd_retval
cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct window_pane *wp = item->state.tflag.wp;
struct window_pane *wp = item->target.wp;
struct paste_buffer *pb;
const char *sepstr, *bufname, *bufdata, *bufend, *line;
size_t seplen, bufsize;

View File

@@ -21,6 +21,7 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -34,16 +35,18 @@
static enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmdq_item *);
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 = {
.name = "pipe-pane",
.alias = "pipep",
.args = { "ot:", 0, 1 },
.usage = "[-o] " CMD_TARGET_PANE_USAGE " [command]",
.args = { "IOot:", 0, 1 },
.usage = "[-IOo] " CMD_TARGET_PANE_USAGE " [command]",
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_pipe_pane_exec
@@ -53,13 +56,14 @@ static enum cmd_retval
cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct window_pane *wp = item->state.tflag.wp;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct client *c = cmd_find_client(item, NULL, 1);
struct window_pane *wp = item->target.wp;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
char *cmd;
int old_fd, pipe_fd[2], null_fd;
int old_fd, pipe_fd[2], null_fd, in, out;
struct format_tree *ft;
sigset_t set, oldset;
/* Destroy the old pipe. */
old_fd = wp->pipe_fd;
@@ -67,6 +71,11 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
bufferevent_free(wp->pipe_event);
close(wp->pipe_fd);
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. */
@@ -82,6 +91,15 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(self->args, 'o') && old_fd != -1)
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. */
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) {
cmdq_error(item, "socketpair error: %s", strerror(errno));
@@ -89,65 +107,119 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
}
/* Expand the command. */
ft = format_create(item, FORMAT_NONE, 0);
ft = format_create(item->client, item, FORMAT_NONE, 0);
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);
/* Fork the child. */
sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, &oldset);
switch (fork()) {
case -1:
sigprocmask(SIG_SETMASK, &oldset, NULL);
cmdq_error(item, "fork error: %s", strerror(errno));
free(cmd);
return (CMD_RETURN_ERROR);
case 0:
/* Child process. */
proc_clear_signals(server_proc, 1);
sigprocmask(SIG_SETMASK, &oldset, NULL);
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);
if (dup2(null_fd, STDOUT_FILENO) == -1)
_exit(1);
if (out) {
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)
_exit(1);
if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO)
close(null_fd);
closefrom(STDERR_FILENO + 1);
execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
_exit(1);
default:
/* Parent process. */
sigprocmask(SIG_SETMASK, &oldset, NULL);
close(pipe_fd[1]);
wp->pipe_fd = pipe_fd[0];
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
wp->pipe_event = bufferevent_new(wp->pipe_fd,
NULL, NULL, cmd_pipe_pane_error_callback, wp);
bufferevent_enable(wp->pipe_event, EV_WRITE);
if (wp->fd != -1)
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
else
wp->pipe_off = 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);
return (CMD_RETURN_NORMAL);
}
}
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,
__unused short what, void *data)
{
struct window_pane *wp = data;
log_debug("%%%u pipe error", wp->id);
bufferevent_free(wp->pipe_event);
close(wp->pipe_fd);
wp->pipe_fd = -1;
if (window_pane_destroy_ready(wp))
server_destroy_pane(wp, 1);
}

View File

@@ -102,8 +102,11 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
static void
cmdq_remove(struct cmdq_item *item)
{
if (item->formats != NULL)
format_free(item->formats);
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);
@@ -150,6 +153,15 @@ cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
struct cmd *cmd;
u_int group = cmdq_next_group();
char *tmp;
struct cmdq_shared *shared;
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);
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
xasprintf(&tmp, "command[%s]", cmd->entry->name);
@@ -161,13 +173,11 @@ cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
item->group = group;
item->flags = flags;
item->shared = shared;
item->cmdlist = cmdlist;
item->cmd = cmd;
if (current != NULL)
cmd_find_copy_state(&item->current, current);
if (m != NULL)
memcpy(&item->mouse, m, sizeof item->mouse);
shared->references++;
cmdlist->references++;
if (first == NULL)
@@ -179,41 +189,63 @@ cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
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;
struct cmd *cmd = item->cmd;
const struct cmd_entry *entry = cmd->entry;
enum cmd_retval retval;
const char *name;
struct cmd_find_state *fsp, fs;
int flags;
flags = !!(cmd->flags & CMD_CONTROL);
cmdq_guard(item, "begin", flags);
if (cmd_prepare_state(cmd, item) != 0) {
retval = CMD_RETURN_ERROR;
goto out;
}
if (item->client == NULL)
item->client = cmd_find_client(item, NULL, CMD_FIND_QUIET);
retval = cmd->entry->exec(cmd, item);
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;
if (cmd->entry->flags & CMD_AFTERHOOK) {
name = cmd->entry->name;
if (cmd_find_valid_state(&item->state.tflag))
fsp = &item->state.tflag;
else {
if (cmd_find_current(&fs, item, CMD_FIND_QUIET) != 0)
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;
}
hooks_insert(fsp->s->hooks, item, fsp, "after-%s", name);
else
goto out;
hooks_insert(fsp->s->hooks, item, fsp, "after-%s", entry->name);
}
out:
@@ -258,19 +290,17 @@ cmdq_fire_callback(struct cmdq_item *item)
void
cmdq_format(struct cmdq_item *item, const char *key, const char *fmt, ...)
{
struct cmdq_shared *shared = item->shared;
va_list ap;
struct cmdq_item *loop;
char *value;
va_start(ap, fmt);
xvasprintf(&value, fmt, ap);
va_end(ap);
for (loop = item; loop != NULL; loop = item->next) {
if (loop->formats == NULL)
loop->formats = format_create(NULL, FORMAT_NONE, 0);
format_add(loop->formats, key, "%s", value);
}
if (shared->formats == NULL)
shared->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
format_add(shared->formats, key, "%s", value);
free(value);
}
@@ -319,8 +349,7 @@ cmdq_next(struct client *c)
item->time = time(NULL);
item->number = ++number;
switch (item->type)
{
switch (item->type) {
case CMDQ_COMMAND:
retval = cmdq_fire_command(item);
@@ -375,10 +404,11 @@ cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
void
cmdq_print(struct cmdq_item *item, const char *fmt, ...)
{
struct client *c = item->client;
struct window *w;
va_list ap;
char *tmp, *msg;
struct client *c = item->client;
struct window_pane *wp;
struct window_mode_entry *wme;
va_list ap;
char *tmp, *msg;
va_start(ap, fmt);
@@ -396,13 +426,11 @@ cmdq_print(struct cmdq_item *item, const char *fmt, ...)
evbuffer_add(c->stdout_data, "\n", 1);
server_client_push_stdout(c);
} else {
w = c->session->curw->window;
if (w->active->mode != &window_copy_mode) {
window_pane_reset_mode(w->active);
window_pane_set_mode(w->active, &window_copy_mode);
window_copy_init_for_output(w->active);
}
window_copy_vadd(w->active, fmt, ap);
wp = c->session->curw->window->active;
wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
window_copy_vadd(wp, fmt, ap);
}
va_end(ap);
@@ -423,6 +451,8 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
msglen = xvasprintf(&msg, fmt, ap);
va_end(ap);
log_debug("%s: %s", __func__, msg);
if (c == NULL)
cfg_add_cause("%s:%u: %s", cmd->file, cmd->line, msg);
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {

View File

@@ -18,6 +18,8 @@
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
@@ -31,10 +33,8 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client",
.alias = "refresh",
.args = { "C:St:", 0, 0 },
.usage = "[-S] [-C size] " CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.args = { "cC:DlLRSt:U", 0, 1 },
.usage = "[-cDlLRSU] [-C size] " CMD_TARGET_CLIENT_USAGE " [adjustment]",
.flags = CMD_AFTERHOOK,
.exec = cmd_refresh_client_exec
@@ -44,21 +44,81 @@ static enum cmd_retval
cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
const char *size;
u_int w, h;
struct client *c;
struct tty *tty;
struct window *w;
const char *size, *errstr;
u_int x, y, adjust;
if (args_has(args, 'C')) {
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
tty = &c->tty;
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 (args_has(args, 'c'))
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;
}
}
tty_update_client_offset(c);
server_redraw_client(c);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'l')) {
if (c->session != NULL)
tty_putcode_ptr2(&c->tty, TTYC_MS, "", "?");
} else if (args_has(args, 'C')) {
if ((size = args_get(args, 'C')) == NULL) {
cmdq_error(item, "missing size");
return (CMD_RETURN_ERROR);
}
if (sscanf(size, "%u,%u", &w, &h) != 2) {
if (sscanf(size, "%u,%u", &x, &y) != 2 &&
sscanf(size, "%ux%u", &x, &y)) {
cmdq_error(item, "bad size argument");
return (CMD_RETURN_ERROR);
}
if (w < PANE_MINIMUM || w > 5000 ||
h < PANE_MINIMUM || h > 5000) {
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);
}
@@ -66,15 +126,18 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}
if (tty_set_size(&c->tty, w, h))
recalculate_sizes();
} else if (args_has(args, 'S')) {
tty_set_size(&c->tty, x, y);
c->flags |= CLIENT_SIZECHANGED;
recalculate_sizes();
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'S')) {
c->flags |= CLIENT_STATUSFORCE;
server_status_client(c);
} else {
c->flags |= CLIENT_STATUSFORCE;
server_redraw_client(c);
}
return (CMD_RETURN_NORMAL);
}

View File

@@ -37,7 +37,7 @@ const struct cmd_entry cmd_rename_session_entry = {
.args = { "t:", 1, 1 },
.usage = CMD_TARGET_SESSION_USAGE " new-name",
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_rename_session_exec
@@ -46,26 +46,31 @@ const struct cmd_entry cmd_rename_session_entry = {
static enum cmd_retval
cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct session *s = item->state.tflag.s;
const char *newname;
struct args *args = self->args;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
char *newname;
newname = args->argv[0];
if (strcmp(newname, s->name) == 0)
newname = format_single(item, args->argv[0], c, s, NULL, NULL);
if (strcmp(newname, s->name) == 0) {
free(newname);
return (CMD_RETURN_NORMAL);
}
if (!session_check_name(newname)) {
cmdq_error(item, "bad session name: %s", newname);
free(newname);
return (CMD_RETURN_ERROR);
}
if (session_find(newname) != NULL) {
cmdq_error(item, "duplicate session: %s", newname);
free(newname);
return (CMD_RETURN_ERROR);
}
RB_REMOVE(sessions, &sessions, s);
free(s->name);
s->name = xstrdup(newname);
s->name = newname;
RB_INSERT(sessions, &sessions, s);
server_status_session(s);

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_rename_window_entry = {
.args = { "t:", 1, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " new-name",
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_rename_window_exec
@@ -46,12 +46,17 @@ static enum cmd_retval
cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct winlink *wl = item->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);
server_status_window(wl->window);
free(newname);
return (CMD_RETURN_NORMAL);
}

View File

@@ -39,7 +39,7 @@ const struct cmd_entry cmd_resize_pane_entry = {
.usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
"[adjustment]",
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_resize_pane_exec
@@ -49,23 +49,24 @@ static enum cmd_retval
cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct window_pane *wp = item->state.tflag.wp;
struct winlink *wl = item->state.tflag.wl;
struct cmdq_shared *shared = item->shared;
struct window_pane *wp = item->target.wp;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct client *c = item->client;
struct session *s = item->state.tflag.s;
struct session *s = item->target.s;
const char *errstr;
char *cause;
u_int adjust;
int x, y;
if (args_has(args, 'M')) {
if (cmd_mouse_window(&item->mouse, &s) == NULL)
if (cmd_mouse_window(&shared->mouse, &s) == NULL)
return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update;
cmd_resize_pane_mouse_update(c, &item->mouse);
cmd_resize_pane_mouse_update(c, &shared->mouse);
return (CMD_RETURN_NORMAL);
}
@@ -90,9 +91,8 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
}
}
if (args_has(self->args, 'x')) {
x = args_strtonum(self->args, 'x', PANE_MINIMUM, INT_MAX,
&cause);
if (args_has(args, 'x')) {
x = args_strtonum(args, 'x', PANE_MINIMUM, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
@@ -100,9 +100,8 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
}
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
}
if (args_has(self->args, 'y')) {
y = args_strtonum(self->args, 'y', PANE_MINIMUM, INT_MAX,
&cause);
if (args_has(args, 'y')) {
y = args_strtonum(args, 'y', PANE_MINIMUM, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "height %s", cause);
free(cause);
@@ -111,13 +110,13 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
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, 1);
else if (args_has(self->args, 'R'))
else if (args_has(args, 'R'))
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, 1);
else if (args_has(self->args, 'D'))
else if (args_has(args, 'D'))
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust, 1);
server_redraw_window(wl->window);
@@ -128,47 +127,64 @@ static void
cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m)
{
struct winlink *wl;
struct window_pane *wp;
int found;
u_int y, ly;
struct window *w;
u_int y, ly, x, lx;
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);
if (wl == NULL) {
c->tty.mouse_drag_update = NULL;
return;
}
w = wl->window;
y = m->y;
y = m->y; x = m->x;
if (m->statusat == 0 && y > 0)
y--;
else if (m->statusat > 0 && y >= (u_int)m->statusat)
y = m->statusat - 1;
ly = m->ly;
ly = m->ly; lx = m->lx;
if (m->statusat == 0 && ly > 0)
ly--;
else if (m->statusat > 0 && ly >= (u_int)m->statusat)
ly = m->statusat - 1;
found = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
if (!window_pane_visible(wp))
for (i = 0; i < nitems(cells); i++) {
lc = layout_search_by_border(w->layout_root, lx + offsets[i][0],
ly + offsets[i][1]);
if (lc == NULL)
continue;
if (wp->xoff + wp->sx == m->lx &&
wp->yoff <= 1 + ly &&
wp->yoff + wp->sy >= ly) {
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, m->x - m->lx, 0);
found = 1;
for (j = 0; j < ncells; j++) {
if (cells[j] == lc) {
lc = NULL;
break;
}
}
if (wp->yoff + wp->sy == ly &&
wp->xoff <= 1 + m->lx &&
wp->xoff + wp->sx >= m->lx) {
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, y - ly, 0);
found = 1;
if (lc == NULL)
continue;
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)
server_redraw_window(wl->window);
else
c->tty.mouse_drag_update = NULL;
if (resizes != 0)
server_redraw_window(w);
}

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

@@ -34,10 +34,11 @@ const struct cmd_entry cmd_respawn_pane_entry = {
.name = "respawn-pane",
.alias = "respawnp",
.args = { "kt:", 0, -1 },
.usage = "[-k] " CMD_TARGET_PANE_USAGE " [command]",
.args = { "c:kt:", 0, -1 },
.usage = "[-c start-directory] [-k] " CMD_TARGET_PANE_USAGE
" [command]",
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_respawn_pane_exec
@@ -47,13 +48,14 @@ static enum cmd_retval
cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct window_pane *wp = item->state.tflag.wp;
struct session *s = item->state.tflag.s;
struct window_pane *wp = item->target.wp;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct environ *env;
const char *path;
char *cause;
const char *path = NULL, *cp;
char *cause, *cwd = NULL;
u_int idx;
struct environ_entry *envent;
@@ -65,11 +67,10 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
window_pane_reset_mode(wp);
window_pane_reset_mode_all(wp);
screen_reinit(&wp->base);
input_init(wp);
path = NULL;
if (item->client != NULL && item->client->session == NULL)
envent = environ_find(item->client->environ, "PATH");
else
@@ -77,15 +78,20 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
if (envent != NULL)
path = envent->value;
env = environ_for_session(s);
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env,
if ((cp = args_get(args, 'c')) != NULL)
cwd = format_single(item, cp, c, s, NULL, NULL);
env = environ_for_session(s, 0);
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, cwd, env,
s->tio, &cause) != 0) {
cmdq_error(item, "respawn pane failed: %s", cause);
free(cause);
environ_free(env);
free(cwd);
return (CMD_RETURN_ERROR);
}
environ_free(env);
free(cwd);
wp->flags |= PANE_REDRAW;
server_status_window(w);

View File

@@ -34,10 +34,11 @@ const struct cmd_entry cmd_respawn_window_entry = {
.name = "respawn-window",
.alias = "respawnw",
.args = { "kt:", 0, -1 },
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
.args = { "c:kt:", 0, -1 },
.usage = "[-c start-directory] [-k] " CMD_TARGET_WINDOW_USAGE
" [command]",
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_respawn_window_exec
@@ -47,13 +48,14 @@ static enum cmd_retval
cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct window_pane *wp;
struct client *c = cmd_find_client(item, NULL, 1);
struct environ *env;
const char *path;
char *cause;
const char *path = NULL, *cp;
char *cause, *cwd = NULL;
struct environ_entry *envent;
if (!args_has(self->args, 'k')) {
@@ -73,7 +75,6 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
window_pane_resize(wp, w->sx, w->sy);
path = NULL;
if (item->client != NULL && item->client->session == NULL)
envent = environ_find(item->client->environ, "PATH");
else
@@ -81,18 +82,24 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
if (envent != NULL)
path = envent->value;
env = environ_for_session(s);
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env,
if ((cp = args_get(args, 'c')) != NULL)
cwd = format_single(item, cp, c, s, NULL, NULL);
env = environ_for_session(s, 0);
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, cwd, env,
s->tio, &cause) != 0) {
cmdq_error(item, "respawn window failed: %s", cause);
free(cause);
environ_free(env);
free(cwd);
server_destroy_pane(wp, 0);
return (CMD_RETURN_ERROR);
}
environ_free(env);
free(cwd);
layout_init(w, wp);
window_pane_reset_mode(wp);
window_pane_reset_mode_all(wp);
screen_reinit(&wp->base);
input_init(wp);
window_set_active_pane(w, wp);

View File

@@ -34,7 +34,7 @@ const struct cmd_entry cmd_rotate_window_entry = {
.args = { "Dt:U", 0, 0 },
.usage = "[-DU] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_rotate_window_exec
@@ -43,7 +43,8 @@ const struct cmd_entry cmd_rotate_window_entry = {
static enum cmd_retval
cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct winlink *wl = item->state.tflag.wl;
struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct window_pane *wp, *wp2;
struct layout_cell *lc;
@@ -77,6 +78,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL)
wp = TAILQ_LAST(&w->panes, window_panes);
window_set_active_pane(w, wp);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
} else {
wp = TAILQ_FIRST(&w->panes);
@@ -104,6 +106,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_NEXT(w->active, entry)) == NULL)
wp = TAILQ_FIRST(&w->panes);
window_set_active_pane(w, wp);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
}

View File

@@ -42,7 +42,7 @@ const struct cmd_entry cmd_run_shell_entry = {
.args = { "bt:", 1, 1 },
.usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
.tflag = CMD_PANE_CANFAIL,
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = 0,
.exec = cmd_run_shell_exec
@@ -57,9 +57,10 @@ struct cmd_run_shell_data {
static void
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 cmd_find_state fs;
struct window_mode_entry *wme;
if (cdata->wp_id != -1)
wp = window_pane_find_by_id(cdata->wp_id);
@@ -68,17 +69,17 @@ cmd_run_shell_print(struct job *job, const char *msg)
cmdq_print(cdata->item, "%s", msg);
return;
}
if (cmd_find_current (&fs, NULL, CMD_FIND_QUIET) != 0)
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)
window_copy_init_for_output(wp);
if (wp->mode == &window_copy_mode)
window_copy_add(wp, "%s", msg);
wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
window_copy_add(wp, "%s", msg);
}
static enum cmd_retval
@@ -86,18 +87,10 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_run_shell_data *cdata;
struct client *c = item->state.c;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct window_pane *wp = item->state.tflag.wp;
const char *cwd;
if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
else if (s != NULL)
cwd = s->cwd;
else
cwd = NULL;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
cdata = xcalloc(1, sizeof *cdata);
cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
@@ -110,8 +103,12 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'b'))
cdata->item = item;
job_run(cdata->cmd, s, cwd, cmd_run_shell_callback, cmd_run_shell_free,
cdata);
if (job_run(cdata->cmd, s, server_client_get_cwd(item->client, s), NULL,
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);
}
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
@@ -121,22 +118,23 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
static void
cmd_run_shell_callback(struct job *job)
{
struct cmd_run_shell_data *cdata = job->data;
char *cmd = cdata->cmd, *msg, *line;
struct cmd_run_shell_data *cdata = job_get_data(job);
struct bufferevent *event = job_get_event(job);
char *cmd = cdata->cmd, *msg = NULL, *line;
size_t size;
int retcode;
int retcode, status;
do {
if ((line = evbuffer_readline(job->event->input)) != NULL) {
if ((line = evbuffer_readline(event->input)) != NULL) {
cmd_run_shell_print(job, line);
free(line);
}
} while (line != NULL);
size = EVBUFFER_LENGTH(job->event->input);
size = EVBUFFER_LENGTH(event->input);
if (size != 0) {
line = xmalloc(size + 1);
memcpy(line, EVBUFFER_DATA(job->event->input), size);
memcpy(line, EVBUFFER_DATA(event->input), size);
line[size] = '\0';
cmd_run_shell_print(job, line);
@@ -144,12 +142,12 @@ cmd_run_shell_callback(struct job *job)
free(line);
}
msg = NULL;
if (WIFEXITED(job->status)) {
if ((retcode = WEXITSTATUS(job->status)) != 0)
status = job_get_status(job);
if (WIFEXITED(status)) {
if ((retcode = WEXITSTATUS(status)) != 0)
xasprintf(&msg, "'%s' returned %d", cmd, retcode);
} else if (WIFSIGNALED(job->status)) {
retcode = WTERMSIG(job->status);
} else if (WIFSIGNALED(status)) {
retcode = WTERMSIG(status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
}
if (msg != NULL)

View File

@@ -59,11 +59,13 @@ static enum cmd_retval
cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->client;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
struct paste_buffer *pb;
const char *path, *bufname, *bufdata, *start, *end;
const char *flags;
char *msg, *file;
const char *bufname, *bufdata, *start, *end, *flags;
char *msg, *path, *file;
size_t size, used, msglen, bufsize;
FILE *f;
@@ -83,10 +85,12 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
bufdata = paste_buffer_data(pb, &bufsize);
if (self->entry == &cmd_show_buffer_entry)
path = "-";
path = xstrdup("-");
else
path = args->argv[0];
path = format_single(item, args->argv[0], c, s, wl, wp);
if (strcmp(path, "-") == 0) {
free(path);
c = item->client;
if (c == NULL) {
cmdq_error(item, "can't write to stdout");
return (CMD_RETURN_ERROR);
@@ -101,6 +105,8 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
flags = "ab";
file = server_client_get_path(c, path);
free(path);
f = fopen(file, flags);
if (f == NULL) {
cmdq_error(item, "%s: %s", file, strerror(errno));
@@ -111,6 +117,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
if (fwrite(bufdata, 1, bufsize, f) != bufsize) {
cmdq_error(item, "%s: write error", file);
fclose(f);
free(file);
return (CMD_RETURN_ERROR);
}

View File

@@ -33,10 +33,10 @@ const struct cmd_entry cmd_select_layout_entry = {
.name = "select-layout",
.alias = "selectl",
.args = { "nopt:", 0, 1 },
.usage = "[-nop] " CMD_TARGET_WINDOW_USAGE " [layout-name]",
.args = { "Enopt:", 0, 1 },
.usage = "[-Enop] " CMD_TARGET_PANE_USAGE " [layout-name]",
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec
@@ -49,7 +49,7 @@ const struct cmd_entry cmd_next_layout_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec
@@ -62,7 +62,7 @@ const struct cmd_entry cmd_previous_layout_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec
@@ -71,14 +71,14 @@ const struct cmd_entry cmd_previous_layout_entry = {
static enum cmd_retval
cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl;
struct window *w;
const char *layoutname;
char *oldlayout;
int next, previous, layout;
struct args *args = self->args;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct window_pane *wp = item->target.wp;
const char *layoutname;
char *oldlayout;
int next, previous, layout;
w = wl->window;
server_unzoom_window(w);
next = self->entry == &cmd_next_layout_entry;
@@ -99,6 +99,11 @@ cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
goto changed;
}
if (args_has(args, 'E')) {
layout_spread_out(wp);
goto changed;
}
if (!args_has(args, 'o')) {
if (args->argc == 0)
layout = w->lastlayout;
@@ -130,7 +135,9 @@ cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
changed:
free(oldlayout);
recalculate_sizes();
server_redraw_window(w);
notify_window("window-layout-changed", w);
return (CMD_RETURN_NORMAL);
error:

View File

@@ -18,6 +18,9 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
@@ -30,10 +33,10 @@ const struct cmd_entry cmd_select_pane_entry = {
.name = "select-pane",
.alias = "selectp",
.args = { "DdegLlMmP:Rt:U", 0, 0 },
.usage = "[-DdegLlMmRU] [-P style] " CMD_TARGET_PANE_USAGE,
.args = { "DdegLlMmP:RT:t:U", 0, 0 },
.usage = "[-DdegLlMmRU] [-P style] [-T title] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_select_pane_exec
@@ -46,41 +49,74 @@ const struct cmd_entry cmd_last_pane_entry = {
.args = { "det:", 0, 0 },
.usage = "[-de] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_select_pane_exec
};
static void
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)
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 winlink *wl = item->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 session *s = item->state.tflag.s;
struct window_pane *wp = item->state.tflag.wp, *lastwp, *markedwp;
struct session *s = item->target.s;
struct window_pane *wp = item->target.wp, *lastwp, *markedwp;
struct style *sy = &wp->style;
char *pane_title;
const char *style;
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
if (wl->window->last == NULL) {
lastwp = w->last;
if (lastwp == NULL && window_count_panes(w) == 2) {
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);
}
if (args_has(self->args, 'e'))
w->last->flags &= ~PANE_INPUTOFF;
lastwp->flags &= ~PANE_INPUTOFF;
else if (args_has(self->args, 'd'))
w->last->flags |= PANE_INPUTOFF;
lastwp->flags |= PANE_INPUTOFF;
else {
server_unzoom_window(w);
window_redraw_active_switch(w, w->last);
if (window_set_active_pane(w, w->last)) {
server_status_window(w);
server_redraw_window_borders(w);
window_redraw_active_switch(w, lastwp);
if (window_set_active_pane(w, lastwp)) {
cmd_find_from_winlink(current, wl, 0);
cmd_select_pane_redraw(w);
}
}
return (CMD_RETURN_NORMAL);
}
@@ -107,17 +143,16 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
}
if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
if (args_has(args, 'P')) {
style = args_get(args, 'P');
if (style_parse(&grid_default_cell, &wp->colgc,
style) == -1) {
if ((style = args_get(args, 'P')) != NULL) {
style_set(sy, &grid_default_cell);
if (style_parse(sy, &grid_default_cell, style) == -1) {
cmdq_error(item, "bad style: %s", style);
return (CMD_RETURN_ERROR);
}
wp->flags |= PANE_REDRAW;
}
if (args_has(self->args, 'g'))
cmdq_print(item, "%s", style_tostring(&wp->colgc));
cmdq_print(item, "%s", style_tostring(sy));
return (CMD_RETURN_NORMAL);
}
@@ -146,17 +181,23 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
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)
return (CMD_RETURN_NORMAL);
server_unzoom_window(wp->window);
if (!window_pane_visible(wp)) {
cmdq_error(item, "pane not visible");
return (CMD_RETURN_ERROR);
}
window_redraw_active_switch(w, wp);
if (window_set_active_pane(w, wp)) {
server_status_window(w);
server_redraw_window_borders(w);
cmd_find_from_winlink_pane(current, wl, wp, 0);
hooks_insert(s->hooks, item, current, "after-select-pane");
cmd_select_pane_redraw(w);
}
return (CMD_RETURN_NORMAL);

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_select_window_entry = {
.args = { "lnpTt:", 0, 0 },
.usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_select_window_exec
@@ -49,7 +49,7 @@ const struct cmd_entry cmd_next_window_entry = {
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_select_window_exec
@@ -62,7 +62,7 @@ const struct cmd_entry cmd_previous_window_entry = {
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_select_window_exec
@@ -75,7 +75,7 @@ const struct cmd_entry cmd_last_window_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_select_window_exec
@@ -84,9 +84,10 @@ const struct cmd_entry cmd_last_window_entry = {
static enum cmd_retval
cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct winlink *wl = item->state.tflag.wl;
struct session *s = item->state.tflag.s;
int next, previous, last, activity;
struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->target.wl;
struct session *s = item->target.s;
int next, previous, last, activity;
next = self->entry == &cmd_next_window_entry;
if (args_has(self->args, 'n'))
@@ -116,8 +117,9 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
}
cmd_find_from_session(current, s, 0);
server_redraw_session(s);
hooks_insert(s->hooks, item, current, "after-select-window");
} else {
/*
* If -T and select-window is invoked on same window as
@@ -128,9 +130,14 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no last window");
return (-1);
}
if (current->s == s)
cmd_find_from_session(current, s, 0);
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);
}
hooks_insert(s->hooks, item, current, "after-select-window");
}
recalculate_sizes();

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_send_keys_entry = {
.args = { "lXRMN:t:", 0, -1 },
.usage = "[-lXRM] [-N repeat-count] " CMD_TARGET_PANE_USAGE " key ...",
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_send_keys_exec
@@ -49,26 +49,55 @@ const struct cmd_entry cmd_send_prefix_entry = {
.args = { "2t:", 0, 0 },
.usage = "[-2] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_send_keys_exec
};
static void
cmd_send_keys_inject(struct client *c, struct cmdq_item *item, key_code key)
{
struct window_pane *wp = item->target.wp;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_mode_entry *wme;
struct key_table *table;
struct key_binding *bd;
wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode->key_table == NULL) {
if (options_get_number(wp->window->options, "xterm-keys"))
key |= KEYC_XTERM;
window_pane_key(wp, NULL, s, wl, key, NULL);
return;
}
table = key_bindings_get_table(wme->mode->key_table(wme), 1);
bd = key_bindings_get(table, key & ~KEYC_XTERM);
if (bd != NULL) {
table->references++;
key_bindings_dispatch(bd, item, c, NULL, &item->target);
key_bindings_unref_table(table);
}
}
static enum cmd_retval
cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct window_pane *wp = item->state.tflag.wp;
struct session *s = item->state.tflag.s;
struct mouse_event *m = &item->mouse;
struct utf8_data *ud, *uc;
wchar_t wc;
int i, literal;
key_code key;
u_int np = 1;
char *cause = NULL;
struct args *args = self->args;
struct client *c = cmd_find_client(item, NULL, 1);
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);
struct utf8_data *ud, *uc;
wchar_t wc;
int i, literal;
key_code key;
u_int np = 1;
char *cause = NULL;
if (args_has(args, 'N')) {
np = args_strtonum(args, 'N', 1, UINT_MAX, &cause);
@@ -77,19 +106,23 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
free(cause);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'X') || args->argc == 0)
wp->modeprefix = np;
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 (wp->mode == NULL || wp->mode->command == NULL) {
if (wme == NULL || wme->mode->command == NULL) {
cmdq_error(item, "not in a mode");
return (CMD_RETURN_ERROR);
}
if (!m->valid)
wp->mode->command(wp, c, s, args, NULL);
else
wp->mode->command(wp, c, s, args, m);
m = NULL;
wme->mode->command(wme, c, s, wl, args, m);
return (CMD_RETURN_NORMAL);
}
@@ -99,7 +132,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no mouse target");
return (CMD_RETURN_ERROR);
}
window_pane_key(wp, NULL, s, m->key, m);
window_pane_key(wp, NULL, s, wl, m->key, m);
return (CMD_RETURN_NORMAL);
}
@@ -108,7 +141,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
key = options_get_number(s->options, "prefix2");
else
key = options_get_number(s->options, "prefix");
window_pane_key(wp, NULL, s, key, NULL);
cmd_send_keys_inject(c, item, key);
return (CMD_RETURN_NORMAL);
}
@@ -123,7 +156,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
if (!literal) {
key = key_string_lookup_string(args->argv[i]);
if (key != KEYC_NONE && key != KEYC_UNKNOWN)
window_pane_key(wp, NULL, s, key, NULL);
cmd_send_keys_inject(c, item, key);
else
literal = 1;
}
@@ -132,7 +165,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
for (uc = ud; uc->size != 0; uc++) {
if (utf8_combine(uc, &wc) != UTF8_DONE)
continue;
window_pane_key(wp, NULL, s, wc, NULL);
cmd_send_keys_inject(c, item, wc);
}
free(ud);
}

View File

@@ -37,7 +37,7 @@ const struct cmd_entry cmd_set_environment_entry = {
.args = { "grt:u", 1, 2 },
.usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
.tflag = CMD_SESSION_CANFAIL,
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_environment_exec
@@ -68,7 +68,7 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(self->args, 'g'))
env = global_environ;
else {
if (item->state.tflag.s == NULL) {
if (item->target.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(item, "no such session: %s", target);
@@ -76,7 +76,7 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
}
env = item->state.tflag.s->environ;
env = item->target.s->environ;
}
if (args_has(self->args, 'u')) {

View File

@@ -33,10 +33,10 @@ 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]",
.args = { "gRt:u", 1, 2 },
.usage = "[-gRu] " CMD_TARGET_SESSION_USAGE " hook-name [command]",
.tflag = CMD_SESSION_CANFAIL,
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_hook_exec
@@ -49,7 +49,7 @@ const struct cmd_entry cmd_show_hooks_entry = {
.args = { "gt:", 0, 1 },
.usage = "[-g] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_hook_exec
@@ -68,7 +68,7 @@ cmd_set_hook_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'g'))
hooks = global_hooks;
else {
if (item->state.tflag.s == NULL) {
if (item->target.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(item, "no such session: %s", target);
@@ -76,7 +76,7 @@ cmd_set_hook_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
}
hooks = item->state.tflag.s->hooks;
hooks = item->target.s->hooks;
}
if (self->entry == &cmd_show_hooks_entry) {
@@ -101,18 +101,21 @@ cmd_set_hook_exec(struct cmd *self, struct cmdq_item *item)
else
cmd = args->argv[1];
if (cmd != NULL && (args_has(args, 'R') || args_has(args, 'u'))) {
cmdq_error(item, "no command allowed");
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'R')) {
notify_hook(item, name);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'u')) {
if (cmd != NULL) {
cmdq_error(item, "command passed to unset hook: %s",
name);
return (CMD_RETURN_ERROR);
}
hooks_remove(hooks, name);
return (CMD_RETURN_NORMAL);
}
if (cmd == NULL) {
cmdq_error(item, "no command to set hook: %s", name);
cmdq_error(item, "no command given");
return (CMD_RETURN_ERROR);
}
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);

View File

@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h>
#include <string.h>
@@ -42,10 +43,10 @@ const struct cmd_entry cmd_set_option_entry = {
.name = "set-option",
.alias = "set",
.args = { "agoqst:uw", 1, 2 },
.usage = "[-agosquw] [-t target-window] option [value]",
.args = { "aFgoqst:uw", 1, 2 },
.usage = "[-aFgosquw] [-t target-window] option [value]",
.tflag = CMD_WINDOW_CANFAIL,
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec
@@ -55,10 +56,10 @@ const struct cmd_entry cmd_set_window_option_entry = {
.name = "set-window-option",
.alias = "setw",
.args = { "agoqt:u", 1, 2 },
.usage = "[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
.args = { "aFgoqt:u", 1, 2 },
.usage = "[-aFgoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
.tflag = CMD_WINDOW_CANFAIL,
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec
@@ -69,33 +70,40 @@ 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->state.tflag;
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 client *c;
enum options_table_scope scope;
struct options *oo;
struct options_entry *parent, *o;
const char *name, *value, *target;
char *name, *argument, *value = NULL, *cause;
const char *target;
int window, idx, already, error, ambiguous;
char *cause;
struct style *sy;
/* Expand argument. */
c = cmd_find_client(item, NULL, 1);
argument = format_single(item, args->argv[0], c, s, wl, NULL);
/* Parse option name and index. */
name = options_match(args->argv[0], &idx, &ambiguous);
name = options_match(argument, &idx, &ambiguous);
if (name == NULL) {
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
goto out;
if (ambiguous)
cmdq_error(item, "ambiguous option: %s", args->argv[0]);
cmdq_error(item, "ambiguous option: %s", argument);
else
cmdq_error(item, "invalid option: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
cmdq_error(item, "invalid option: %s", argument);
goto fail;
}
if (args->argc < 2)
value = NULL;
else if (args_has(args, 'F'))
value = format_single(item, args->argv[1], c, s, wl, NULL);
else
value = args->argv[1];
value = xstrdup(args->argv[1]);
/*
* Figure out the scope: for user options it comes from the arguments,
@@ -113,15 +121,15 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
scope = OPTIONS_TABLE_WINDOW;
else {
scope = OPTIONS_TABLE_NONE;
xasprintf(&cause, "unknown option: %s", args->argv[0]);
xasprintf(&cause, "unknown option: %s", argument);
}
}
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
goto out;
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
goto fail;
}
/* Which table should this option go into? */
@@ -136,7 +144,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no such session: %s", target);
else
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
goto fail;
} else
oo = s->options;
} else if (scope == OPTIONS_TABLE_WINDOW) {
@@ -148,7 +156,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no such window: %s", target);
else
cmdq_error(item, "no current window");
return (CMD_RETURN_ERROR);
goto fail;
} else
oo = wl->window->options;
}
@@ -156,11 +164,9 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
parent = options_get(oo, name);
/* Check that array options and indexes match up. */
if (idx != -1) {
if (*name == '@' || options_array_size(parent, NULL) == -1) {
cmdq_error(item, "not an array: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
if (idx != -1 && (*name == '@' || !options_isarray(parent))) {
cmdq_error(item, "not an array: %s", argument);
goto fail;
}
/* With -o, check this option is not already set. */
@@ -175,18 +181,20 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
}
if (already) {
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
cmdq_error(item, "already set: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
goto out;
cmdq_error(item, "already set: %s", argument);
goto fail;
}
}
/* Change the option. */
if (args_has(args, 'u')) {
if (o == NULL)
return (CMD_RETURN_NORMAL);
goto out;
if (idx == -1) {
if (oo == global_options ||
if (*name == '@')
options_remove(o);
else if (oo == global_options ||
oo == global_s_options ||
oo == global_w_options)
options_default(oo, options_table_entry(o));
@@ -197,17 +205,17 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
} else if (*name == '@') {
if (value == NULL) {
cmdq_error(item, "empty value");
return (CMD_RETURN_ERROR);
goto fail;
}
options_set_string(oo, name, append, "%s", value);
} else if (idx == -1 && options_array_size(parent, NULL) == -1) {
} else if (idx == -1 && !options_isarray(parent)) {
error = cmd_set_option_set(self, item, oo, parent, value);
if (error != 0)
return (CMD_RETURN_ERROR);
goto fail;
} else {
if (value == NULL) {
cmdq_error(item, "empty value");
return (CMD_RETURN_ERROR);
goto fail;
}
if (o == NULL)
o = options_empty(oo, options_table_entry(parent));
@@ -216,8 +224,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
options_array_clear(o);
options_array_assign(o, value);
} else if (options_array_set(o, idx, value, append) != 0) {
cmdq_error(item, "invalid index: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
cmdq_error(item, "invalid index: %s", argument);
goto fail;
}
}
@@ -231,8 +239,24 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
}
}
if (strcmp(name, "key-table") == 0) {
TAILQ_FOREACH(c, &clients, entry)
server_client_set_key_table(c, NULL);
TAILQ_FOREACH(loop, &clients, entry)
server_client_set_key_table(loop, NULL);
}
if (strcmp(name, "user-keys") == 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)
@@ -246,22 +270,32 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
}
if (strcmp(name, "pane-border-status") == 0) {
RB_FOREACH(w, windows, &windows)
layout_fix_panes(w, w->sx, w->sy);
layout_fix_panes(w);
}
RB_FOREACH (s, sessions, &sessions)
status_update_saved(s);
RB_FOREACH(s, sessions, &sessions)
status_update_cache(s);
/*
* Update sizes and redraw. May not always be necessary but do it
* anyway.
*/
recalculate_sizes();
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != NULL)
server_redraw_client(c);
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->session != NULL)
server_redraw_client(loop);
}
out:
free(argument);
free(value);
free(name);
return (CMD_RETURN_NORMAL);
fail:
free(argument);
free(value);
free(name);
return (CMD_RETURN_ERROR);
}
static int
@@ -273,7 +307,8 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
int append = args_has(args, 'a');
struct options_entry *o;
long long number;
const char *errstr;
const char *errstr, *new;
char *old;
key_code key;
oe = options_table_entry(parent);
@@ -286,7 +321,16 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
switch (oe->type) {
case OPTIONS_TABLE_STRING:
old = xstrdup(options_get_string(oo, oe->name));
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:
number = strtonum(value, oe->minimum, oe->maximum, &errstr);
@@ -309,16 +353,7 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
cmdq_error(item, "bad colour: %s", value);
return (-1);
}
o = options_set_number(oo, oe->name, number);
options_style_update_new(oo, o);
return (0);
case OPTIONS_TABLE_ATTRIBUTES:
if ((number = attributes_fromstring(value)) == -1) {
cmdq_error(item, "bad attributes: %s", value);
return (-1);
}
o = options_set_number(oo, oe->name, number);
options_style_update_new(oo, o);
options_set_number(oo, oe->name, number);
return (0);
case OPTIONS_TABLE_FLAG:
return (cmd_set_option_flag(item, oe, oo, value));
@@ -330,7 +365,6 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
cmdq_error(item, "bad style: %s", value);
return (-1);
}
options_style_update_old(oo, o);
return (0);
case OPTIONS_TABLE_ARRAY:
break;

View File

@@ -41,7 +41,7 @@ const struct cmd_entry cmd_show_environment_entry = {
.args = { "gst:", 0, 1 },
.usage = "[-gs] " CMD_TARGET_SESSION_USAGE " [name]",
.tflag = CMD_SESSION_CANFAIL,
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_show_environment_exec
@@ -97,7 +97,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
const char *target;
if ((target = args_get(args, 't')) != NULL) {
if (item->state.tflag.s == NULL) {
if (item->target.s == NULL) {
cmdq_error(item, "no such session: %s", target);
return (CMD_RETURN_ERROR);
}
@@ -106,7 +106,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(self->args, 'g'))
env = global_environ;
else {
if (item->state.tflag.s == NULL) {
if (item->target.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(item, "no such session: %s", target);
@@ -114,7 +114,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
}
env = item->state.tflag.s->environ;
env = item->target.s->environ;
}
if (args->argc != 0) {

View File

@@ -38,14 +38,11 @@ const struct cmd_entry cmd_show_messages_entry = {
.args = { "JTt:", 0, 0 },
.usage = "[-JT] " CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = CMD_AFTERHOOK,
.exec = cmd_show_messages_exec
};
static int cmd_show_messages_terminals(struct cmdq_item *, int);
static int cmd_show_messages_jobs(struct cmdq_item *, int);
static int
cmd_show_messages_terminals(struct cmdq_item *item, int blank)
@@ -68,41 +65,25 @@ cmd_show_messages_terminals(struct cmdq_item *item, int blank)
return (n != 0);
}
static int
cmd_show_messages_jobs(struct cmdq_item *item, int blank)
{
struct job *job;
u_int n;
n = 0;
LIST_FOREACH(job, &all_jobs, lentry) {
if (blank) {
cmdq_print(item, "%s", "");
blank = 0;
}
cmdq_print(item, "Job %u: %s [fd=%d, pid=%ld, status=%d]",
n, job->cmd, job->fd, (long)job->pid, job->status);
n++;
}
return (n != 0);
}
static enum cmd_retval
cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct client *c;
struct message_entry *msg;
char *tim;
int done, blank;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
done = blank = 0;
if (args_has(args, 'T')) {
blank = cmd_show_messages_terminals(item, blank);
done = 1;
}
if (args_has(args, 'J')) {
cmd_show_messages_jobs(item, blank);
job_print_summary(item, blank);
done = 1;
}
if (done)

View File

@@ -41,7 +41,7 @@ const struct cmd_entry cmd_show_options_entry = {
.args = { "gqst:vw", 0, 1 },
.usage = "[-gqsvw] [-t target-session|target-window] [option]",
.tflag = CMD_WINDOW_CANFAIL,
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec
@@ -54,7 +54,7 @@ const struct cmd_entry cmd_show_window_options_entry = {
.args = { "gvt:", 0, 1 },
.usage = "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]",
.tflag = CMD_WINDOW_CANFAIL,
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec
@@ -64,7 +64,7 @@ static enum cmd_retval
cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_find_state *fs = &item->state.tflag;
struct cmd_find_state *fs = &item->target;
struct options *oo;
enum options_table_scope scope;
char *cause;
@@ -88,20 +88,20 @@ static void
cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
struct options_entry *o, int idx)
{
const char *name;
const char *value;
char *tmp, *escaped;
u_int size, i;
struct options_array_item *a;
const char *name, *value;
char *tmp, *escaped;
if (idx != -1) {
xasprintf(&tmp, "%s[%d]", options_name(o), idx);
name = tmp;
} else {
if (options_array_size(o, &size) != -1) {
for (i = 0; i < size; i++) {
if (options_array_get(o, i) == NULL)
continue;
cmd_show_options_print(self, item, o, i);
if (options_isarray(o)) {
a = options_array_first(o);
while (a != NULL) {
idx = options_array_item_index(a);
cmd_show_options_print(self, item, o, idx);
a = options_array_next(a);
}
return;
}
@@ -127,25 +127,36 @@ cmd_show_options_one(struct cmd *self, struct cmdq_item *item,
struct options *oo)
{
struct args *args = self->args;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct options_entry *o;
int idx, ambiguous;
const char *name = args->argv[0];
char *name;
name = format_single(item, args->argv[0], c, s, wl, NULL);
o = options_match_get(oo, name, &idx, 1, &ambiguous);
if (o == NULL) {
if (args_has(args, 'q'))
if (args_has(args, 'q')) {
free(name);
return (CMD_RETURN_NORMAL);
}
if (ambiguous) {
cmdq_error(item, "ambiguous option: %s", name);
free(name);
return (CMD_RETURN_ERROR);
}
if (*name != '@' &&
options_match_get(oo, name, &idx, 0, &ambiguous) != NULL)
options_match_get(oo, name, &idx, 0, &ambiguous) != NULL) {
free(name);
return (CMD_RETURN_NORMAL);
}
cmdq_error(item, "unknown option: %s", name);
free(name);
return (CMD_RETURN_ERROR);
}
cmd_show_options_print(self, item, o, idx);
free(name);
return (CMD_RETURN_NORMAL);
}
@@ -153,24 +164,22 @@ static enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmdq_item *item,
struct options *oo)
{
struct options_entry *o;
struct options_entry *o;
const struct options_table_entry *oe;
u_int size, idx;
struct options_array_item *a;
u_int idx;
o = options_first(oo);
while (o != NULL) {
oe = options_table_entry(o);
if (oe != NULL && oe->style != NULL) {
o = options_next(o);
continue;
}
if (options_array_size(o, &size) == -1)
if (!options_isarray(o))
cmd_show_options_print(self, item, o, -1);
else {
for (idx = 0; idx < size; idx++) {
if (options_array_get(o, idx) == NULL)
continue;
a = options_array_first(o);
while (a != NULL) {
idx = options_array_item_index(a);
cmd_show_options_print(self, item, o, idx);
a = options_array_next(a);
}
}
o = options_next(o);

View File

@@ -60,7 +60,7 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
if (*path == '/')
pattern = xstrdup(path);
else {
utf8_stravis(&tmp, server_client_get_cwd(c), VIS_GLOB);
utf8_stravis(&tmp, server_client_get_cwd(c, NULL), VIS_GLOB);
xasprintf(&pattern, "%s/%s", tmp, path);
free(tmp);
}

View File

@@ -43,7 +43,7 @@ const struct cmd_entry cmd_split_window_entry = {
.usage = "[-bdfhvP] [-c start-directory] [-F format] "
"[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]",
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_split_window_exec
@@ -52,17 +52,18 @@ const struct cmd_entry cmd_split_window_entry = {
static enum cmd_retval
cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct cmd_find_state *current = &item->shared->current;
struct args *args = self->args;
struct client *c = item->state.c;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->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 window *w = wl->window;
struct window_pane *wp = item->state.tflag.wp, *new_wp = NULL;
struct window_pane *wp = item->target.wp, *new_wp = NULL;
struct environ *env;
const char *cmd, *path, *shell, *template, *cwd, *to_free;
char **argv, *cause, *new_cause, *cp;
const char *cmd, *path, *shell, *template, *tmp;
char **argv, *cause, *new_cause, *cp, *cwd;
u_int hlimit;
int argc, size, percentage;
int argc, size, percentage, before;
enum layout_type type;
struct layout_cell *lc;
struct environ_entry *envent;
@@ -84,18 +85,15 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
argv = args->argv;
}
to_free = NULL;
if (args_has(args, 'c')) {
cwd = args_get(args, 'c');
to_free = cwd = format_single(item, cwd, c, s, NULL, NULL);
} else if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
if ((tmp = args_get(args, 'c')) != NULL)
cwd = format_single(item, tmp, c, s, NULL, NULL);
else
cwd = s->cwd;
cwd = xstrdup(server_client_get_cwd(item->client, s));
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT;
before = args_has(args, 'b');
size = -1;
if (args_has(args, 'l')) {
@@ -125,14 +123,13 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (*shell == '\0' || areshell(shell))
shell = _PATH_BSHELL;
lc = layout_split_pane(wp, type, size, args_has(args, 'b'),
args_has(args, 'f'));
lc = layout_split_pane(wp, type, size, before, args_has(args, 'f'));
if (lc == NULL) {
cause = xstrdup("pane too small");
goto error;
}
new_wp = window_add_pane(w, wp, args_has(args, 'b'), hlimit);
layout_assign_pane(lc, new_wp);
new_wp = window_add_pane(w, wp, before, args_has(args, 'f'), hlimit);
layout_make_leaf(lc, new_wp);
path = NULL;
if (item->client != NULL && item->client->session == NULL)
@@ -142,7 +139,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (envent != NULL)
path = envent->value;
env = environ_for_session(s);
env = environ_for_session(s, 0);
if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, env,
s->tio, &cause) != 0) {
environ_free(env);
@@ -150,11 +147,13 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
}
environ_free(env);
layout_fix_panes(w);
server_redraw_window(w);
if (!args_has(args, 'd')) {
window_set_active_pane(w, new_wp);
session_select(s, wl->idx);
cmd_find_from_session(current, s, 0);
server_redraw_session(s);
} else
server_status_session(s);
@@ -168,17 +167,10 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
}
notify_window("window-layout-changed", w);
if (to_free != NULL)
free((void *)to_free);
cmd_find_clear_state(&fs, NULL, 0);
fs.s = s;
fs.wl = wl;
fs.w = w;
fs.wp = new_wp;
cmd_find_log_state(__func__, &fs);
cmd_find_from_winlink_pane(&fs, wl, new_wp, 0);
hooks_insert(s->hooks, item, &fs, "after-split-window");
free(cwd);
return (CMD_RETURN_NORMAL);
error:
@@ -189,7 +181,6 @@ error:
cmdq_error(item, "create pane failed: %s", cause);
free(cause);
if (to_free != NULL)
free((void *)to_free);
free(cwd);
return (CMD_RETURN_ERROR);
}

View File

@@ -54,6 +54,22 @@ cmd_string_ungetc(size_t *p)
(*p)--;
}
static int
cmd_string_unicode(wchar_t *wc, const char *s, size_t *p, char ch)
{
int size = (ch == 'u') ? 4 : 8;
u_int tmp;
if (size == 4 && sscanf(s + *p, "%4x", &tmp) != 1)
return (-1);
if (size == 8 && sscanf(s + *p, "%8x", &tmp) != 1)
return (-1);
*p += size;
*wc = (wchar_t)tmp;
return (0);
}
int
cmd_string_split(const char *s, int *rargc, char ***rargv)
{
@@ -159,21 +175,19 @@ cmd_string_parse(const char *s, const char *file, u_int line, char **cause)
char **argv;
*cause = NULL;
if (cmd_string_split(s, &argc, &argv) != 0)
goto error;
if (cmd_string_split(s, &argc, &argv) != 0) {
xasprintf(cause, "invalid or unknown command: %s", s);
return (NULL);
}
if (argc != 0) {
cmdlist = cmd_list_parse(argc, argv, file, line, cause);
if (cmdlist == NULL) {
cmd_free_argv(argc, argv);
goto error;
return (NULL);
}
}
cmd_free_argv(argc, argv);
return (cmdlist);
error:
xasprintf(cause, "invalid or unknown command: %s", s);
return (NULL);
}
static void
@@ -193,12 +207,11 @@ cmd_string_copy(char **dst, char *src, size_t *len)
static 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;
int ch;
wchar_t wc;
struct utf8_data ud;
char *buf = NULL, *t;
size_t len = 0;
while ((ch = cmd_string_getc(s, p)) != endch) {
switch (ch) {
@@ -222,6 +235,18 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc)
case 't':
ch = '\t';
break;
case 'u':
case 'U':
if (cmd_string_unicode(&wc, s, p, ch) != 0)
goto error;
if (utf8_split(wc, &ud) != UTF8_DONE)
goto error;
if (len >= SIZE_MAX - ud.size - 1)
goto error;
buf = xrealloc(buf, len + ud.size);
memcpy(buf + len, ud.data, ud.size);
len += ud.size;
continue;
}
break;
case '$':

View File

@@ -35,8 +35,8 @@ const struct cmd_entry cmd_swap_pane_entry = {
.args = { "dDs:t:U", 0, 0 },
.usage = "[-dDU] " CMD_SRCDST_PANE_USAGE,
.sflag = CMD_PANE_MARKED,
.tflag = CMD_PANE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_swap_pane_exec
@@ -50,10 +50,10 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
struct layout_cell *src_lc, *dst_lc;
u_int sx, sy, xoff, yoff;
dst_w = item->state.tflag.wl->window;
dst_wp = item->state.tflag.wp;
src_w = item->state.sflag.wl->window;
src_wp = item->state.sflag.wp;
dst_w = item->target.wl->window;
dst_wp = item->target.wp;
src_w = item->source.wl->window;
src_wp = item->source.wp;
server_unzoom_window(dst_w);
if (args_has(self->args, 'D')) {
@@ -105,8 +105,6 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
window_set_active_pane(dst_w, src_wp);
} else {
tmp_wp = dst_wp;
if (!window_pane_visible(tmp_wp))
tmp_wp = src_wp;
window_set_active_pane(src_w, tmp_wp);
}
} else {

View File

@@ -35,8 +35,8 @@ const struct cmd_entry cmd_swap_window_entry = {
.args = { "ds:t:", 0, 0 },
.usage = "[-d] " CMD_SRCDST_WINDOW_USAGE,
.sflag = CMD_WINDOW_MARKED,
.tflag = CMD_WINDOW,
.source = { 's', CMD_FIND_WINDOW, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_swap_window_exec
@@ -50,12 +50,12 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
struct winlink *wl_src, *wl_dst;
struct window *w_src, *w_dst;
wl_src = item->state.sflag.wl;
src = item->state.sflag.s;
wl_src = item->source.wl;
src = item->source.s;
sg_src = session_group_contains(src);
wl_dst = item->state.tflag.wl;
dst = item->state.tflag.s;
wl_dst = item->target.wl;
dst = item->target.s;
sg_dst = session_group_contains(dst);
if (src != dst && sg_src != NULL && sg_dst != NULL &&

View File

@@ -38,8 +38,7 @@ const struct cmd_entry cmd_switch_client_entry = {
.usage = "[-Elnpr] [-c target-client] [-t target-session] "
"[-T key-table]",
.cflag = CMD_CLIENT,
.tflag = CMD_SESSION_WITHPANE,
/* -t is special */
.flags = CMD_READONLY,
.exec = cmd_switch_client_exec
@@ -49,13 +48,32 @@ static enum cmd_retval
cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_state *state = &item->state;
struct client *c = state->c;
struct session *s = item->state.tflag.s;
const char *tflag = args_get(args, 't');
enum cmd_find_type type;
int flags;
struct client *c;
struct session *s;
struct winlink *wl;
struct window_pane *wp;
const char *tablename;
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'))
c->flags ^= CLIENT_READONLY;
@@ -94,11 +112,14 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
} else {
if (item->client == NULL)
return (CMD_RETURN_NORMAL);
if (state->tflag.wl != NULL) {
wp = state->tflag.wp;
if (wp != NULL)
if (wl != NULL) {
server_unzoom_window(wl->window);
if (wp != NULL) {
window_redraw_active_switch(wp->window, wp);
window_set_active_pane(wp->window, wp);
session_set_current(s, state->tflag.wl);
}
session_set_current(s, wl);
cmd_find_from_session(&item->shared->current, s, 0);
}
}
@@ -108,9 +129,11 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
if (c->session != NULL && c->session != s)
c->last_session = c->session;
c->session = s;
if (!item->repeat)
if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);

View File

@@ -170,7 +170,7 @@ cmd_wait_for_wait(struct cmdq_item *item, const char *name,
struct client *c = item->client;
struct wait_item *wi;
if (c == NULL || c->session != NULL) {
if (c == NULL) {
cmdq_error(item, "not able to wait");
return (CMD_RETURN_ERROR);
}
@@ -198,7 +198,7 @@ cmd_wait_for_lock(struct cmdq_item *item, const char *name,
{
struct wait_item *wi;
if (item->client == NULL || item->client->session != NULL) {
if (item->client == NULL) {
cmdq_error(item, "not able to lock");
return (CMD_RETURN_ERROR);
}

241
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_choose_buffer_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_window_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_command_prompt_entry;
@@ -82,6 +80,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_window_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_window_entry;
extern const struct cmd_entry cmd_rotate_window_entry;
@@ -122,9 +121,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_capture_pane_entry,
&cmd_choose_buffer_entry,
&cmd_choose_client_entry,
&cmd_choose_session_entry,
&cmd_choose_tree_entry,
&cmd_choose_window_entry,
&cmd_clear_history_entry,
&cmd_clock_mode_entry,
&cmd_command_prompt_entry,
@@ -170,6 +167,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_rename_session_entry,
&cmd_rename_window_entry,
&cmd_resize_pane_entry,
&cmd_resize_window_entry,
&cmd_respawn_pane_entry,
&cmd_respawn_window_entry,
&cmd_rotate_window_entry,
@@ -204,6 +202,15 @@ const struct cmd_entry *cmd_table[] = {
NULL
};
void
cmd_log_argv(int argc, char **argv, const char *prefix)
{
int i;
for (i = 0; i < argc; i++)
log_debug("%s: argv[%d]=%s", prefix, i, argv[i]);
}
int
cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
{
@@ -212,6 +219,7 @@ cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
if (argc == 0)
return (0);
cmd_log_argv(argc, argv, __func__);
*buf = '\0';
for (i = 0; i < argc; i++) {
@@ -244,9 +252,11 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
arglen = strlen(buf) + 1;
(*argv)[i] = xstrdup(buf);
buf += arglen;
len -= arglen;
}
cmd_log_argv(argc, *argv, __func__);
return (0);
}
@@ -308,31 +318,31 @@ cmd_stringify_argv(int argc, char **argv)
static int
cmd_try_alias(int *argc, char ***argv)
{
struct options_entry *o;
int old_argc = *argc, new_argc;
char **old_argv = *argv, **new_argv;
u_int size, idx;
int i;
size_t wanted;
const char *s, *cp = NULL;
struct options_entry *o;
struct options_array_item *a;
int old_argc = *argc, new_argc, i;
char **old_argv = *argv, **new_argv;
size_t wanted;
const char *s, *cp = NULL;
o = options_get_only(global_options, "command-alias");
if (o == NULL || options_array_size(o, &size) == -1 || size == 0)
if (o == NULL)
return (-1);
wanted = strlen(old_argv[0]);
for (idx = 0; idx < size; idx++) {
s = options_array_get(o, idx);
if (s == NULL)
continue;
cp = strchr(s, '=');
if (cp == NULL || (size_t)(cp - s) != wanted)
continue;
if (strncmp(old_argv[0], s, wanted) == 0)
break;
a = options_array_first(o);
while (a != NULL) {
s = options_array_item_value(a);
if (s != NULL) {
cp = strchr(s, '=');
if (cp != NULL &&
(size_t)(cp - s) == wanted &&
strncmp(old_argv[0], s, wanted) == 0)
break;
}
a = options_array_next(a);
}
if (idx == size)
if (a == NULL)
return (-1);
if (cmd_string_split(cp + 1, &new_argc, &new_argv) != 0)
@@ -405,6 +415,7 @@ retry:
xasprintf(cause, "unknown command: %s", name);
return (NULL);
}
cmd_log_argv(argc, argv, entry->name);
args = args_parse(entry->args.template, argc, argv);
if (args == NULL)
@@ -447,190 +458,6 @@ usage:
return (NULL);
}
static int
cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
struct cmdq_item *item)
{
int targetflags, error;
struct cmd_find_state *fs = NULL;
struct cmd_find_state current;
if (flag == CMD_NONE ||
flag == CMD_CLIENT ||
flag == CMD_CLIENT_CANFAIL)
return (0);
if (c == 't')
fs = &item->state.tflag;
else if (c == 's')
fs = &item->state.sflag;
if (flag == CMD_SESSION_WITHPANE) {
if (target != NULL && target[strcspn(target, ":.")] != '\0')
flag = CMD_PANE;
else
flag = CMD_SESSION_PREFERUNATTACHED;
}
targetflags = 0;
switch (flag) {
case CMD_SESSION:
case CMD_SESSION_CANFAIL:
case CMD_SESSION_PREFERUNATTACHED:
case CMD_SESSION_WITHPANE:
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);
error = cmd_find_current(&current, item, targetflags);
if (error != 0) {
if (~targetflags & CMD_FIND_QUIET)
return (-1);
cmd_find_clear_state(&current, NULL, 0);
}
if (!cmd_find_empty_state(&current) && !cmd_find_valid_state(&current))
fatalx("invalid current state");
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, item, target,
CMD_FIND_SESSION, targetflags);
if (error != 0)
goto error;
break;
case CMD_MOVEW_R:
error = cmd_find_target(fs, &current, item, 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, item, target,
CMD_FIND_WINDOW, targetflags);
if (error != 0)
goto error;
break;
case CMD_PANE:
case CMD_PANE_CANFAIL:
case CMD_PANE_MARKED:
error = cmd_find_target(fs, &current, item, target,
CMD_FIND_PANE, targetflags);
if (error != 0)
goto error;
break;
default:
fatalx("unknown %cflag %d", c, flag);
}
return (0);
error:
if (~targetflags & CMD_FIND_QUIET)
return (-1);
cmd_find_clear_state(fs, NULL, 0);
return (0);
}
int
cmd_prepare_state(struct cmd *cmd, struct cmdq_item *item)
{
const struct cmd_entry *entry = cmd->entry;
struct cmd_state *state = &item->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, item->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(item, s, 0);
if (state->c == NULL)
return (-1);
break;
default:
state->c = cmd_find_client(item, s, 1);
break;
}
log_debug("using client %p", state->c);
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, item);
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, item);
if (error != 0)
return (error);
if (!cmd_find_empty_state(&state->tflag) &&
!cmd_find_valid_state(&state->tflag))
fatalx("invalid -t state");
if (!cmd_find_empty_state(&state->sflag) &&
!cmd_find_valid_state(&state->sflag))
fatalx("invalid -s state");
return (0);
}
char *
cmd_print(struct cmd *cmd)
{

View File

@@ -141,6 +141,8 @@ colour_tostring(int c)
return ("white");
case 8:
return ("default");
case 9:
return ("terminal");
case 90:
return ("brightblack");
case 91:
@@ -158,7 +160,7 @@ colour_tostring(int c)
case 97:
return ("brightwhite");
}
return (NULL);
return ("invalid");
}
/* Convert colour from string. */
@@ -188,6 +190,11 @@ colour_fromstring(const char *s)
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)
return (0);
if (strcasecmp(s, "red") == 0 || strcmp(s, "1") == 0)
@@ -204,8 +211,6 @@ colour_fromstring(const char *s)
return (6);
if (strcasecmp(s, "white") == 0 || strcmp(s, "7") == 0)
return (7);
if (strcasecmp(s, "default") == 0 || strcmp(s, "8") == 0)
return (8);
if (strcasecmp(s, "brightblack") == 0 || strcmp(s, "90") == 0)
return (90);
if (strcasecmp(s, "brightred") == 0 || strcmp(s, "91") == 0)

View File

@@ -18,6 +18,7 @@
#define COMPAT_H
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <limits.h>
@@ -100,17 +101,17 @@ void warnx(const char *, ...);
#include <paths.h>
#endif
#ifdef HAVE_FORKPTY
#ifdef HAVE_LIBUTIL_H
#include <libutil.h>
#endif
#ifdef HAVE_PTY_H
#include <pty.h>
#endif
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
#endif
#ifdef HAVE_VIS
#include <vis.h>
@@ -260,6 +261,11 @@ size_t strnlen(const char *, size_t);
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
/* daemon.c */
int daemon(int, int);
@@ -283,9 +289,15 @@ 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
#ifndef HAVE_FORKPTY
/* forkpty.c */
#include <sys/ioctl.h>
pid_t forkpty(int *, char *, struct termios *, struct winsize *);
#endif
@@ -337,9 +349,7 @@ int utf8proc_mbtowc(wchar_t *, const char *, size_t);
int utf8proc_wctomb(char *, wchar_t);
#endif
#ifdef HAVE_GETOPT
#include <getopt.h>
#else
#ifndef HAVE_GETOPT
/* getopt.c */
extern int BSDopterr;
extern int BSDoptind;

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

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

@@ -29,7 +29,8 @@ void fatal(const char *, ...);
void fatalx(const char *, ...);
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];
char *path, dummy;

View File

@@ -30,19 +30,12 @@ getdtablecount(void)
{
char path[PATH_MAX];
glob_t g;
int n;
int n = 0;
if (snprintf(path, sizeof path, "/proc/%ld/fd/*", (long)getpid()) < 0)
fatal("snprintf overflow");
switch (glob(path, 0, NULL, &g)) {
case GLOB_NOMATCH:
return (0);
case 0:
break;
default:
fatal("glob(\"%s\") failed", path);
}
n = g.gl_pathc;
if (glob(path, 0, NULL, &g) == 0)
n = g.gl_pathc;
globfree(&g);
return (n);
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: imsg-buffer.c,v 1.10 2017/04/11 09:57:19 reyk Exp $ */
/* $OpenBSD: imsg-buffer.c,v 1.11 2017/12/14 09:27:44 kettenis Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -29,9 +29,9 @@
#include "compat.h"
#include "imsg.h"
int ibuf_realloc(struct ibuf *, size_t);
void ibuf_enqueue(struct msgbuf *, struct ibuf *);
void ibuf_dequeue(struct msgbuf *, struct ibuf *);
static int ibuf_realloc(struct ibuf *, size_t);
static void ibuf_enqueue(struct msgbuf *, struct ibuf *);
static void ibuf_dequeue(struct msgbuf *, struct ibuf *);
struct ibuf *
ibuf_open(size_t len)
@@ -67,7 +67,7 @@ ibuf_dynamic(size_t len, size_t max)
return (buf);
}
int
static int
ibuf_realloc(struct ibuf *buf, size_t len)
{
u_char *b;
@@ -289,14 +289,14 @@ again:
return (1);
}
void
static void
ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
{
TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
msgbuf->queued++;
}
void
static void
ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
{
TAILQ_REMOVE(&msgbuf->bufs, buf, entry);

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: imsg.c,v 1.15 2017/04/11 09:57:19 reyk Exp $ */
/* $OpenBSD: imsg.c,v 1.16 2017/12/14 09:27:44 kettenis Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -30,7 +30,7 @@
int imsg_fd_overhead = 0;
int imsg_get_fd(struct imsgbuf *);
static int imsg_get_fd(struct imsgbuf *);
void
imsg_init(struct imsgbuf *ibuf, int fd)
@@ -266,7 +266,7 @@ imsg_free(struct imsg *imsg)
freezero(imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE);
}
int
static int
imsg_get_fd(struct imsgbuf *ibuf)
{
int fd;

65
compat/memmem.c Normal file
View File

@@ -0,0 +1,65 @@
/* $OpenBSD: memmem.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */
/*-
* Copyright (c) 2005 Pascal Gloor <pascal.gloor@spale.com>
*
* 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.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <string.h>
#include "compat.h"
/*
* Find the first occurrence of the byte string s in byte string l.
*/
void *
memmem(const void *l, size_t l_len, const void *s, size_t s_len)
{
const char *cur, *last;
const char *cl = l;
const char *cs = s;
/* a zero length needle should just return the haystack */
if (s_len == 0)
return (void *)cl;
/* "s" must be smaller or equal to "l" */
if (l_len < s_len)
return NULL;
/* special case where s_len == 1 */
if (s_len == 1)
return memchr(l, *cs, l_len);
/* the last position where its possible to find "s" in "l" */
last = cl + l_len - s_len;
for (cur = cl; cur <= last; cur++)
if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
return (void *)cur;
return NULL;
}

View File

@@ -15,13 +15,15 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "compat.h"
int
setenv(const char *name, const char *value, unused int overwrite)
setenv(const char *name, const char *value, __unused int overwrite)
{
char *newval;

View File

@@ -1,6 +1,6 @@
# configure.ac
AC_INIT(tmux, 2.4)
AC_INIT([tmux], 2.9)
AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc)
@@ -35,6 +35,7 @@ AC_USE_SYSTEM_EXTENSIONS
test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc
# Is this --enable-debug?
case "x$VERSION" in xnext*) enable_debug=yes;; esac
AC_ARG_ENABLE(
debug,
AC_HELP_STRING(--enable-debug, enable debug build flags),
@@ -103,10 +104,10 @@ AC_REPLACE_FUNCS([ \
closefrom \
explicit_bzero \
fgetln \
fparseln \
freezero \
getdtablecount \
getprogname \
memmem \
recallocarray \
reallocarray \
setenv \
@@ -175,7 +176,8 @@ if test "x$found_ncurses" = xno; then
)
fi
if test "x$found_ncurses" = xyes; then
CPPFLAGS="$LIBNCURSES_CFLAGS $LIBTINFO_CFLAGS $CPPFLAGS"
AM_CFLAGS="$LIBNCURSES_CFLAGS $LIBTINFO_CFLAGS $AM_CFLAGS"
CFLAGS="$LIBNCURSES_CFLAGS $LIBTINFO_CFLAGS $CFLAGS"
LIBS="$LIBNCURSES_LIBS $LIBTINFO_LIBS $LIBS"
else
# pkg-config didn't work, try ncurses.
@@ -283,6 +285,7 @@ if test "x$found_b64_ntop" = xno; then
AC_MSG_RESULT(no)
AC_MSG_CHECKING(for b64_ntop with -lresolv)
OLD_LIBS="$LIBS"
LIBS="$LIBS -lresolv"
AC_TRY_LINK(
[
@@ -295,6 +298,7 @@ if test "x$found_b64_ntop" = xno; then
found_b64_ntop=no
)
if test "x$found_b64_ntop" = xno; then
LIBS="$OLD_LIBS"
AC_MSG_RESULT(no)
fi
fi
@@ -453,13 +457,30 @@ else
AC_LIBOBJ(getopt)
fi
# Look for forkpty in libutil. compat/forkpty-*.c is linked if not found.
# Look for fparseln in libutil.
AC_SEARCH_LIBS(fparseln, util, found_fparseln=yes, found_fparseln=no)
if test "x$found_fparseln" = xyes; then
AC_DEFINE(HAVE_FPARSELN)
else
AC_LIBOBJ(fparseln)
fi
# Look for fdforkpty and forkpty in libutil.
AC_SEARCH_LIBS(fdforkpty, util, found_fdforkpty=yes, found_fdforkpty=no)
if test "x$found_fdforkpty" = xyes; then
AC_DEFINE(HAVE_FDFORKPTY)
else
AC_LIBOBJ(fdforkpty)
fi
AC_SEARCH_LIBS(forkpty, util, found_forkpty=yes, found_forkpty=no)
if test "x$found_forkpty" = xyes; then
AC_DEFINE(HAVE_FORKPTY)
fi
AM_CONDITIONAL(NEED_FORKPTY, test "x$found_forkpty" = xno)
# Look for kinfo_getfile in libutil.
AC_SEARCH_LIBS(kinfo_getfile, [util util-freebsd])
# Look for a suitable queue.h.
AC_CHECK_DECL(
TAILQ_CONCAT,
@@ -555,8 +576,15 @@ case "$host_os" in
;;
*darwin*)
AC_MSG_RESULT(darwin)
AC_DEFINE(BROKEN_CMSG_FIRSTHDR)
PLATFORM=darwin
#
# OS X CMSG_FIRSTHDR is broken, so redefine it with a working
# one. daemon works but has some stupid side effects, so use
# our internal version which has a workaround.
#
AC_DEFINE(BROKEN_CMSG_FIRSTHDR)
AC_LIBOBJ(daemon)
AC_LIBOBJ(daemon-darwin)
;;
*dragonfly*)
AC_MSG_RESULT(dragonfly)
@@ -585,13 +613,22 @@ case "$host_os" in
*solaris*)
AC_MSG_RESULT(sunos)
PLATFORM=sunos
MANFORMAT=man
case `/usr/bin/nroff --version 2>&1` in
*GNU*)
# Solaris 11.4 and later use GNU groff.
MANFORMAT=mdoc
;;
*)
# Solaris 2.0 to 11.3 use AT&T nroff.
MANFORMAT=man
;;
esac
;;
*hpux*)
AC_MSG_RESULT(hpux)
PLATFORM=hpux
;;
*cygwin*)
*cygwin*|*msys*)
AC_MSG_RESULT(cygwin)
PLATFORM=cygwin
;;

View File

@@ -47,6 +47,8 @@ control_notify_input(struct client *c, struct window_pane *wp,
*/
if (winlink_find_by_window(&c->session->windows, wp->window) != NULL) {
message = evbuffer_new();
if (message == NULL)
fatalx("out of memory");
evbuffer_add_printf(message, "%%output %%%u ", wp->id);
for (i = 0; i < len; i++) {
if (buf[i] < ' ' || buf[i] == '\\')
@@ -59,14 +61,27 @@ control_notify_input(struct client *c, struct window_pane *wp,
}
}
void
control_notify_pane_mode_changed(int pane)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
control_write(c, "%%pane-mode-changed %%%u", pane);
}
}
void
control_notify_window_layout_changed(struct window *w)
{
struct client *c;
struct session *s;
struct winlink *wl;
const char *template;
char *cp;
struct client *c;
struct session *s;
struct winlink *wl;
const char *template;
char *cp;
template = "%layout-change #{window_id} #{window_layout} "
"#{window_visible_layout} #{window_flags}";
@@ -96,6 +111,20 @@ control_notify_window_layout_changed(struct window *w)
}
}
void
control_notify_window_pane_changed(struct window *w)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
control_write(c, "%%window-pane-changed @%u %%%u", w->id,
w->active->id);
}
}
void
control_notify_window_unlinked(__unused struct session *s, struct window *w)
{
@@ -154,15 +183,27 @@ control_notify_window_renamed(struct window *w)
}
void
control_notify_client_session_changed(struct client *c)
control_notify_client_session_changed(struct client *cc)
{
struct client *c;
struct session *s;
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
if (cc->session == NULL)
return;
s = c->session;
s = cc->session;
control_write(c, "%%session-changed $%u %s", s->id, s->name);
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
continue;
if (cc == c) {
control_write(c, "%%session-changed $%u %s", s->id,
s->name);
} else {
control_write(c, "%%client-session-changed %s $%u %s",
cc->name, s->id, s->name);
}
}
}
void
@@ -203,3 +244,17 @@ control_notify_session_closed(__unused struct session *s)
control_write(c, "%%sessions-changed");
}
}
void
control_notify_session_window_changed(struct session *s)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
control_write(c, "%%session-window-changed $%u @%u", s->id,
s->curw->window->id);
}
}

View File

@@ -174,22 +174,26 @@ environ_unset(struct environ *env, const char *name)
void
environ_update(struct options *oo, struct environ *src, struct environ *dst)
{
struct environ_entry *envent;
struct options_entry *o;
u_int size, idx;
const char *value;
struct environ_entry *envent;
struct options_entry *o;
struct options_array_item *a;
const char *value;
o = options_get(oo, "update-environment");
if (o == NULL || options_array_size(o, &size) == -1)
if (o == NULL)
return;
for (idx = 0; idx < size; idx++) {
value = options_array_get(o, idx);
if (value == NULL)
a = options_array_first(o);
while (a != NULL) {
value = options_array_item_value(a);
if (value == NULL) {
a = options_array_next(a);
continue;
}
if ((envent = environ_find(src, value)) == NULL)
environ_clear(dst, value);
else
environ_set(dst, envent->name, "%s", envent->value);
a = options_array_next(a);
}
}
@@ -208,9 +212,15 @@ environ_push(struct environ *env)
/* Log the environment. */
void
environ_log(struct environ *env, const char *prefix)
environ_log(struct environ *env, const char *fmt, ...)
{
struct environ_entry *envent;
va_list ap;
char *prefix;
va_start(ap, fmt);
vasprintf(&prefix, fmt, ap);
va_end(ap);
RB_FOREACH(envent, environ, env) {
if (envent->value != NULL && *envent->name != '\0') {
@@ -218,11 +228,13 @@ environ_log(struct environ *env, const char *prefix)
envent->value);
}
}
free(prefix);
}
/* Create initial environment for new child. */
struct environ *
environ_for_session(struct session *s)
environ_for_session(struct session *s, int no_TERM)
{
struct environ *env;
const char *value;
@@ -233,8 +245,10 @@ environ_for_session(struct session *s)
if (s != NULL)
environ_copy(s->environ, env);
value = options_get_string(global_options, "default-terminal");
environ_set(env, "TERM", "%s", value);
if (!no_TERM) {
value = options_get_string(global_options, "default-terminal");
environ_set(env, "TERM", "%s", value);
}
if (s != NULL)
idx = s->id;

View File

@@ -49,11 +49,15 @@ bind F10 selectw -t:19
bind F11 selectw -t:20
bind F12 selectw -t:21
# Keys to toggle monitoring activity in a window, and synchronize-panes
# A key to toggle between smallest and largest sizes if a window is visible in
# multiple places
bind F set -w window-size
# Keys to toggle monitoring activity in a window and the synchronize-panes option
bind m set monitor-activity
bind y set synchronize-panes\; display 'synchronize-panes #{?synchronize-panes,on,off}'
# Create a single default session, because a session is created here, tmux
# Create a single default session - because a session is created here, tmux
# should be started with "tmux attach" rather than "tmux new"
new -d -s0 -nirssi 'exec irssi'
set -t0:0 monitor-activity on

892
format-draw.c Normal file
View File

@@ -0,0 +1,892 @@
/* $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"
/* Format range. */
struct format_range {
u_int index;
struct screen *s;
u_int start;
u_int end;
enum style_range_type type;
u_int argument;
TAILQ_ENTRY(format_range) entry;
};
TAILQ_HEAD(format_ranges, format_range);
/* Does this range match this style? */
static int
format_is_type(struct format_range *fr, struct style *sy)
{
if (fr->type != sy->range_type)
return (0);
if (fr->type == STYLE_RANGE_WINDOW &&
fr->argument != sy->range_argument)
return (0);
return (1);
}
/* Free a range. */
static void
format_free_range(struct format_ranges *frs, struct format_range *fr)
{
TAILQ_REMOVE(frs, fr, entry);
free(fr);
}
/* Fix range positions. */
static void
format_update_ranges(struct format_ranges *frs, struct screen *s, u_int offset,
u_int start, u_int width)
{
struct format_range *fr, *fr1;
if (frs == NULL)
return;
TAILQ_FOREACH_SAFE(fr, frs, entry, fr1) {
if (fr->s != s)
continue;
if (fr->end <= start || fr->start >= start + width) {
format_free_range(frs, fr);
continue;
}
if (fr->start < start)
fr->start = start;
if (fr->end > start + width)
fr->end = start + width;
if (fr->start == fr->end) {
format_free_range(frs, fr);
continue;
}
fr->start -= start;
fr->end -= start;
fr->start += offset;
fr->end += offset;
}
}
/* Draw a part of the format. */
static void
format_draw_put(struct screen_write_ctx *octx, u_int ocx, u_int ocy,
struct screen *s, struct format_ranges *frs, u_int offset, u_int start,
u_int width)
{
/*
* The offset is how far from the cursor on the target screen; start
* and width how much to copy from the source screen.
*/
screen_write_cursormove(octx, ocx + offset, ocy, 0);
screen_write_fast_copy(octx, s, start, 0, width, 1);
format_update_ranges(frs, s, offset, start, width);
}
/* Draw list part of format. */
static void
format_draw_put_list(struct screen_write_ctx *octx,
u_int ocx, u_int ocy, u_int offset, u_int width, struct screen *list,
struct screen *list_left, struct screen *list_right, int focus_start,
int focus_end, struct format_ranges *frs)
{
u_int start, focus_centre;
/* If there is enough space for the list, draw it entirely. */
if (width >= list->cx) {
format_draw_put(octx, ocx, ocy, list, frs, offset, 0, width);
return;
}
/* The list needs to be trimmed. Try to keep the focus visible. */
focus_centre = focus_start + (focus_end - focus_start) / 2;
if (focus_centre < width / 2)
start = 0;
else
start = focus_centre - width / 2;
if (start + width > list->cx)
start = list->cx - width;
/* Draw <> markers at either side if needed. */
if (start != 0 && width > list_left->cx) {
screen_write_cursormove(octx, ocx + offset, ocy, 0);
screen_write_fast_copy(octx, list_left, 0, 0, list_left->cx, 1);
offset += list_left->cx;
start += list_left->cx;
width -= list_left->cx;
}
if (start + width < list->cx && width > list_right->cx) {
screen_write_cursormove(octx, ocx + offset + width - 1, ocy, 0);
screen_write_fast_copy(octx, list_right, 0, 0, list_right->cx,
1);
width -= list_right->cx;
}
/* Draw the list screen itself. */
format_draw_put(octx, ocx, ocy, list, frs, offset, start, width);
}
/* Draw format with no list. */
static void
format_draw_none(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct format_ranges *frs)
{
u_int width_left, width_centre, width_right;
width_left = left->cx;
width_centre = centre->cx;
width_right = right->cx;
/*
* Try to keep as much of the left and right as possible at the expense
* of the centre.
*/
while (width_left + width_centre + width_right > available) {
if (width_centre > 0)
width_centre--;
else if (width_right > 0)
width_right--;
else
width_left--;
}
/* Write left. */
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
/* Write right at available - width_right. */
format_draw_put(octx, ocx, ocy, right, frs,
available - width_right,
right->cx - width_right,
width_right);
/*
* Write centre halfway between
* width_left
* and
* available - width_right.
*/
format_draw_put(octx, ocx, ocy, centre, frs,
width_left
+ ((available - width_right) - width_left) / 2
- width_centre / 2,
centre->cx / 2 - width_centre / 2,
width_centre);
}
/* Draw format with list on the left. */
static void
format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct screen *list, struct screen *list_left, struct screen *list_right,
struct screen *after, int focus_start, int focus_end,
struct format_ranges *frs)
{
u_int width_left, width_centre, width_right;
u_int width_list, width_after;
struct screen_write_ctx ctx;
width_left = left->cx;
width_centre = centre->cx;
width_right = right->cx;
width_list = list->cx;
width_after = after->cx;
/*
* Trim first the centre, then the list, then the right, then after the
* list, then the left.
*/
while (width_left +
width_centre +
width_right +
width_list +
width_after > available) {
if (width_centre > 0)
width_centre--;
else if (width_list > 0)
width_list--;
else if (width_right > 0)
width_right--;
else if (width_after > 0)
width_after--;
else
width_left--;
}
/* If there is no list left, pass off to the no list function. */
if (width_list == 0) {
screen_write_start(&ctx, NULL, left);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx);
format_draw_none(octx, available, ocx, ocy, left, centre,
right, frs);
return;
}
/* Write left at 0. */
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
/* Write right at available - width_right. */
format_draw_put(octx, ocx, ocy, right, frs,
available - width_right,
right->cx - width_right,
width_right);
/* Write after at width_left + width_list. */
format_draw_put(octx, ocx, ocy, after, frs,
width_left + width_list,
0,
width_after);
/*
* Write centre halfway between
* width_left + width_list + width_after
* and
* available - width_right.
*/
format_draw_put(octx, ocx, ocy, centre, frs,
(width_left + width_list + width_after)
+ ((available - width_right)
- (width_left + width_list + width_after)) / 2
- width_centre / 2,
centre->cx / 2 - width_centre / 2,
width_centre);
/*
* The list now goes from
* width_left
* to
* width_left + width_list.
* If there is no focus given, keep the left in focus.
*/
if (focus_start == -1 || focus_end == -1)
focus_start = focus_end = 0;
format_draw_put_list(octx, ocx, ocy, width_left, width_list, list,
list_left, list_right, focus_start, focus_end, frs);
}
/* Draw format with list in the centre. */
static void
format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct screen *list, struct screen *list_left, struct screen *list_right,
struct screen *after, int focus_start, int focus_end,
struct format_ranges *frs)
{
u_int width_left, width_centre, width_right;
u_int width_list, width_after, middle;
struct screen_write_ctx ctx;
width_left = left->cx;
width_centre = centre->cx;
width_right = right->cx;
width_list = list->cx;
width_after = after->cx;
/*
* Trim first the list, then after the list, then the centre, then the
* right, then the left.
*/
while (width_left +
width_centre +
width_right +
width_list +
width_after > available) {
if (width_list > 0)
width_list--;
else if (width_after > 0)
width_after--;
else if (width_centre > 0)
width_centre--;
else if (width_right > 0)
width_right--;
else
width_left--;
}
/* If there is no list left, pass off to the no list function. */
if (width_list == 0) {
screen_write_start(&ctx, NULL, centre);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx);
format_draw_none(octx, available, ocx, ocy, left, centre,
right, frs);
return;
}
/* Write left at 0. */
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
/* Write after at available - width_after. */
format_draw_put(octx, ocx, ocy, after, frs,
available - width_after,
after->cx - width_after,
width_after);
/* Write right at available - width_right. */
format_draw_put(octx, ocx, ocy, right, frs,
available - width_right,
right->cx - width_right,
width_right);
/*
* All three centre sections are offset from the middle of the
* available space.
*/
middle = (width_left + ((available - width_right) - width_left) / 2);
/*
* Write centre at
* middle - width_list / 2 - width_centre.
*/
format_draw_put(octx, ocx, ocy, centre, frs,
middle - width_list / 2 - width_centre,
0,
width_centre);
/*
* Write after at
* middle + width_list / 2 - width_centre.
*/
format_draw_put(octx, ocx, ocy, after, frs,
middle + width_list / 2,
0,
width_after);
/*
* The list now goes from
* middle - width_list / 2
* to
* middle + width_list / 2
* If there is no focus given, keep the centre in focus.
*/
if (focus_start == -1 || focus_end == -1)
focus_start = focus_end = list->cx / 2;
format_draw_put_list(octx, ocx, ocy, middle - width_list / 2,
width_list, list, list_left, list_right, focus_start, focus_end,
frs);
}
/* Draw format with list on the right. */
static void
format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct screen *list, struct screen *list_left, struct screen *list_right,
struct screen *after, int focus_start, int focus_end,
struct format_ranges *frs)
{
u_int width_left, width_centre, width_right;
u_int width_list, width_after;
struct screen_write_ctx ctx;
width_left = left->cx;
width_centre = centre->cx;
width_right = right->cx;
width_list = list->cx;
width_after = after->cx;
/*
* Trim first the centre, then the list, then the right, then
* after the list, then the left.
*/
while (width_left +
width_centre +
width_right +
width_list +
width_after > available) {
if (width_centre > 0)
width_centre--;
else if (width_list > 0)
width_list--;
else if (width_right > 0)
width_right--;
else if (width_after > 0)
width_after--;
else
width_left--;
}
/* If there is no list left, pass off to the no list function. */
if (width_list == 0) {
screen_write_start(&ctx, NULL, right);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx);
format_draw_none(octx, available, ocx, ocy, left, centre,
right, frs);
return;
}
/* Write left at 0. */
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
/* Write after at available - width_after. */
format_draw_put(octx, ocx, ocy, after, frs,
available - width_after,
after->cx - width_after,
width_after);
/*
* Write right at
* available - width_right - width_list - width_after.
*/
format_draw_put(octx, ocx, ocy, right, frs,
available - width_right - width_list - width_after,
0,
width_right);
/*
* Write centre halfway between
* width_left
* and
* available - width_right - width_list - width_after.
*/
format_draw_put(octx, ocx, ocy, centre, frs,
width_left
+ ((available - width_right - width_list - width_after)
- width_left) / 2
- width_centre / 2,
centre->cx / 2 - width_centre / 2,
width_centre);
/*
* The list now goes from
* available - width_list - width_after
* to
* available - width_after
* If there is no focus given, keep the right in focus.
*/
if (focus_start == -1 || focus_end == -1)
focus_start = focus_end = 0;
format_draw_put_list(octx, ocx, ocy, available - width_list -
width_after, width_list, list, list_left, list_right, focus_start,
focus_end, frs);
}
/* Draw a format to a screen. */
void
format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
u_int available, const char *expanded, struct style_ranges *srs)
{
enum { LEFT,
CENTRE,
RIGHT,
LIST,
LIST_LEFT,
LIST_RIGHT,
AFTER,
TOTAL } current = LEFT, last = LEFT;
const char *names[] = { "LEFT",
"CENTRE",
"RIGHT",
"LIST",
"LIST_LEFT",
"LIST_RIGHT",
"AFTER" };
size_t size = strlen(expanded);
struct screen *os = octx->s, s[TOTAL];
struct screen_write_ctx ctx[TOTAL];
u_int ocx = os->cx, ocy = os->cy, i, width[TOTAL];
u_int map[] = { LEFT, LEFT, CENTRE, RIGHT };
int focus_start = -1, focus_end = -1;
int list_state = -1;
enum style_align list_align = STYLE_ALIGN_DEFAULT;
struct style sy;
struct utf8_data *ud = &sy.gc.data;
const char *cp, *end;
enum utf8_state more;
char *tmp;
struct format_range *fr = NULL, *fr1;
struct format_ranges frs;
struct style_range *sr;
style_set(&sy, base);
TAILQ_INIT(&frs);
log_debug("%s: %s", __func__, expanded);
/*
* We build three screens for left, right, centre alignment, one for
* the list, one for anything after the list and two for the list left
* and right markers.
*/
for (i = 0; i < TOTAL; i++) {
screen_init(&s[i], size, 1, 0);
screen_write_start(&ctx[i], NULL, &s[i]);
screen_write_clearendofline(&ctx[i], base->bg);
width[i] = 0;
}
/*
* Walk the string and add to the corresponding screens,
* parsing styles as we go.
*/
cp = expanded;
while (*cp != '\0') {
if (cp[0] != '#' || cp[1] != '[') {
/* See if this is a UTF-8 character. */
if ((more = utf8_open(ud, *cp)) == UTF8_MORE) {
while (*++cp != '\0' && more == UTF8_MORE)
more = utf8_append(ud, *cp);
if (more != UTF8_DONE)
cp -= ud->have;
}
/* Not a UTF-8 character - ASCII or not valid. */
if (more != UTF8_DONE) {
if (*cp < 0x20 || *cp > 0x7e) {
/* Ignore nonprintable characters. */
cp++;
continue;
}
utf8_set(ud, *cp);
cp++;
}
/* Draw the cell to th current screen. */
screen_write_cell(&ctx[current], &sy.gc);
width[current] += ud->width;
continue;
}
/* This is a style. Work out where the end is and parse it. */
end = format_skip(cp + 2, "]");
if (end == NULL) {
log_debug("%s: no terminating ] at '%s'", __func__,
cp + 2);
TAILQ_FOREACH_SAFE(fr, &frs, entry, fr1)
format_free_range(&frs, fr);
goto out;
}
tmp = xstrndup(cp + 2, end - (cp + 2));
if (style_parse(&sy, base, tmp) != 0) {
log_debug("%s: invalid style '%s'", __func__, tmp);
free(tmp);
cp = end + 1;
continue;
}
log_debug("%s: style '%s' -> '%s'", __func__, tmp,
style_tostring(&sy));
free(tmp);
/* Check the list state. */
switch (sy.list) {
case STYLE_LIST_ON:
/*
* Entering the list, exiting a marker, or exiting the
* focus.
*/
if (list_state != 0) {
if (fr != NULL) { /* abort any region */
free(fr);
fr = NULL;
}
list_state = 0;
list_align = sy.align;
}
/* End the focus if started. */
if (focus_start != -1 && focus_end == -1)
focus_end = s[LIST].cx;
current = LIST;
break;
case STYLE_LIST_FOCUS:
/* Entering the focus. */
if (list_state != 0) /* not inside the list */
break;
if (focus_start == -1) /* focus already started */
focus_start = s[LIST].cx;
break;
case STYLE_LIST_OFF:
/* Exiting or outside the list. */
if (list_state == 0) {
if (fr != NULL) { /* abort any region */
free(fr);
fr = NULL;
}
if (focus_start != -1 && focus_end == -1)
focus_end = s[LIST].cx;
map[list_align] = AFTER;
if (list_align == STYLE_ALIGN_LEFT)
map[STYLE_ALIGN_DEFAULT] = AFTER;
list_state = 1;
}
current = map[sy.align];
break;
case STYLE_LIST_LEFT_MARKER:
/* Entering left marker. */
if (list_state != 0) /* not inside the list */
break;
if (s[LIST_LEFT].cx != 0) /* already have marker */
break;
if (fr != NULL) { /* abort any region */
free(fr);
fr = NULL;
}
if (focus_start != -1 && focus_end == -1)
focus_start = focus_end = -1;
current = LIST_LEFT;
break;
case STYLE_LIST_RIGHT_MARKER:
/* Entering right marker. */
if (list_state != 0) /* not inside the list */
break;
if (s[LIST_RIGHT].cx != 0) /* already have marker */
break;
if (fr != NULL) { /* abort any region */
free(fr);
fr = NULL;
}
if (focus_start != -1 && focus_end == -1)
focus_start = focus_end = -1;
current = LIST_RIGHT;
break;
}
if (current != last) {
log_debug("%s: change %s -> %s", __func__,
names[last], names[current]);
last = current;
}
/*
* Check if the range style has changed and if so end the
* current range and start a new one if needed.
*/
if (srs != NULL) {
if (fr != NULL && !format_is_type(fr, &sy)) {
if (s[current].cx != fr->start) {
fr->end = s[current].cx + 1;
TAILQ_INSERT_TAIL(&frs, fr, entry);
} else
free(fr);
fr = NULL;
}
if (fr == NULL && sy.range_type != STYLE_RANGE_NONE) {
fr = xcalloc(1, sizeof *fr);
fr->index = current;
fr->s = &s[current];
fr->start = s[current].cx;
fr->type = sy.range_type;
fr->argument = sy.range_argument;
}
}
cp = end + 1;
}
free(fr);
for (i = 0; i < TOTAL; i++) {
screen_write_stop(&ctx[i]);
log_debug("%s: width %s is %u", __func__, names[i], width[i]);
}
if (focus_start != -1 && focus_end != -1)
log_debug("%s: focus %d-%d", __func__, focus_start, focus_end);
TAILQ_FOREACH(fr, &frs, entry) {
log_debug("%s: range %d|%u is %s %u-%u", __func__, fr->type,
fr->argument, names[fr->index], fr->start, fr->end);
}
/*
* Draw the screens. How they are arranged depends on where the list
* appearsq.
*/
switch (list_align) {
case STYLE_ALIGN_DEFAULT:
/* No list. */
format_draw_none(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &frs);
break;
case STYLE_ALIGN_LEFT:
/* List is part of the left. */
format_draw_left(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
&s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
break;
case STYLE_ALIGN_CENTRE:
/* List is part of the centre. */
format_draw_centre(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
&s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
break;
case STYLE_ALIGN_RIGHT:
/* List is part of the right. */
format_draw_right(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
&s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
break;
}
/* Create ranges to return. */
TAILQ_FOREACH_SAFE(fr, &frs, entry, fr1) {
sr = xcalloc(1, sizeof *sr);
sr->type = fr->type;
sr->argument = fr->argument;
sr->start = fr->start;
sr->end = fr->end;
TAILQ_INSERT_TAIL(srs, sr, entry);
log_debug("%s: range %d|%u at %u-%u", __func__, sr->type,
sr->argument, sr->start, sr->end);
format_free_range(&frs, fr);
}
out:
/* Free the screens. */
for (i = 0; i < TOTAL; i++)
screen_free(&s[i]);
/* Restore the original cursor position. */
screen_write_cursormove(octx, ocx, ocy, 0);
}
/* Get width, taking #[] into account. */
u_int
format_width(const char *expanded)
{
const char *cp, *end;
u_int width = 0;
struct utf8_data ud;
enum utf8_state more;
cp = expanded;
while (*cp != '\0') {
if (cp[0] == '#' && cp[1] == '[') {
end = format_skip(cp + 2, "]");
if (end == NULL)
return 0;
cp = end + 1;
} else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
while (*++cp != '\0' && more == UTF8_MORE)
more = utf8_append(&ud, *cp);
if (more == UTF8_DONE)
width += ud.width;
else
cp -= ud.have;
} else if (*cp > 0x1f && *cp < 0x7f) {
width++;
cp++;
}
}
return (width);
}
/* Trim on the left, taking #[] into account. */
char *
format_trim_left(const char *expanded, u_int limit)
{
char *copy, *out;
const char *cp = expanded, *end;
u_int width = 0;
struct utf8_data ud;
enum utf8_state more;
out = copy = xmalloc(strlen(expanded) + 1);
while (*cp != '\0') {
if (cp[0] == '#' && cp[1] == '[') {
end = format_skip(cp + 2, "]");
if (end == NULL)
break;
memcpy(out, cp, end + 1 - cp);
out += (end + 1 - cp);
cp = end + 1;
} else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
while (*++cp != '\0' && more == UTF8_MORE)
more = utf8_append(&ud, *cp);
if (more == UTF8_DONE) {
if (width + ud.width <= limit) {
memcpy(out, ud.data, ud.size);
out += ud.size;
}
width += ud.width;
} else
cp -= ud.have;
} else if (*cp > 0x1f && *cp < 0x7f) {
if (width + 1 <= limit)
*out++ = *cp;
width++;
cp++;
} else
cp++;
}
*out = '\0';
return (copy);
}
/* Trim on the right, taking #[] into account. */
char *
format_trim_right(const char *expanded, u_int limit)
{
char *copy, *out;
const char *cp = expanded, *end;
u_int width = 0, total_width, skip;
struct utf8_data ud;
enum utf8_state more;
total_width = format_width(expanded);
if (total_width <= limit)
return (xstrdup(expanded));
skip = total_width - limit;
out = copy = xmalloc(strlen(expanded) + 1);
while (*cp != '\0') {
if (cp[0] == '#' && cp[1] == '[') {
end = format_skip(cp + 2, "]");
if (end == NULL)
break;
memcpy(out, cp, end + 1 - cp);
out += (end + 1 - cp);
cp = end + 1;
} else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
while (*++cp != '\0' && more == UTF8_MORE)
more = utf8_append(&ud, *cp);
if (more == UTF8_DONE) {
if (width >= skip) {
memcpy(out, ud.data, ud.size);
out += ud.size;
}
width += ud.width;
} else
cp -= ud.have;
} else if (*cp > 0x1f && *cp < 0x7f) {
if (width >= skip)
*out++ = *cp;
width++;
cp++;
} else
cp++;
}
*out = '\0';
return (copy);
}

1313
format.c

File diff suppressed because it is too large Load Diff

View File

@@ -64,7 +64,7 @@ grid_view_clear_history(struct grid *gd, u_int bg)
/* Find the last used line. */
last = 0;
for (yy = 0; yy < gd->sy; yy++) {
gl = &gd->linedata[grid_view_y(gd, yy)];
gl = grid_get_line(gd, grid_view_y(gd, yy));
if (gl->cellused != 0)
last = yy + 1;
}
@@ -75,7 +75,7 @@ grid_view_clear_history(struct grid *gd, u_int bg)
/* Scroll the lines into the history. */
for (yy = 0; yy < last; yy++) {
grid_collect_history(gd, bg);
grid_collect_history(gd);
grid_scroll_history(gd, bg);
}
if (last < gd->sy)
@@ -96,32 +96,34 @@ grid_view_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny,
/* Scroll region up. */
void
grid_view_scroll_region_up(struct grid *gd, u_int rupper, u_int rlower)
grid_view_scroll_region_up(struct grid *gd, u_int rupper, u_int rlower,
u_int bg)
{
if (gd->flags & GRID_HISTORY) {
grid_collect_history(gd, 8);
grid_collect_history(gd);
if (rupper == 0 && rlower == gd->sy - 1)
grid_scroll_history(gd, 8);
grid_scroll_history(gd, bg);
else {
rupper = grid_view_y(gd, rupper);
rlower = grid_view_y(gd, rlower);
grid_scroll_history_region(gd, rupper, rlower);
grid_scroll_history_region(gd, rupper, rlower, bg);
}
} else {
rupper = grid_view_y(gd, rupper);
rlower = grid_view_y(gd, rlower);
grid_move_lines(gd, rupper, rupper + 1, rlower - rupper, 8);
grid_move_lines(gd, rupper, rupper + 1, rlower - rupper, bg);
}
}
/* Scroll region down. */
void
grid_view_scroll_region_down(struct grid *gd, u_int rupper, u_int rlower)
grid_view_scroll_region_down(struct grid *gd, u_int rupper, u_int rlower,
u_int bg)
{
rupper = grid_view_y(gd, rupper);
rlower = grid_view_y(gd, rlower);
grid_move_lines(gd, rupper + 1, rupper, rlower - rupper, 8);
grid_move_lines(gd, rupper + 1, rupper, rlower - rupper, bg);
}
/* Insert lines. */

877
grid.c

File diff suppressed because it is too large Load Diff

27
hooks.c
View File

@@ -139,33 +139,6 @@ hooks_find(struct hooks *hooks, const char *name)
return (hook);
}
void
hooks_run(struct hooks *hooks, struct client *c, struct cmd_find_state *fs,
const char *fmt, ...)
{
struct hook *hook;
va_list ap;
char *name;
struct cmdq_item *new_item;
va_start(ap, fmt);
xvasprintf(&name, fmt, ap);
va_end(ap);
hook = hooks_find(hooks, name);
if (hook == NULL) {
free(name);
return;
}
log_debug("running hook %s", name);
new_item = cmdq_get_command(hook->cmdlist, fs, NULL, CMDQ_NOHOOKS);
cmdq_format(new_item, "hook", "%s", name);
cmdq_append(c, new_item);
free(name);
}
void
hooks_insert(struct hooks *hooks, struct cmdq_item *item,
struct cmd_find_state *fs, const char *fmt, ...)

View File

@@ -45,6 +45,10 @@ static const struct input_key_ent input_keys[] = {
/* Backspace key. */
{ KEYC_BSPACE, "\177", 0 },
/* Paste keys. */
{ KEYC_PASTE_START, "\033[200~", 0 },
{ KEYC_PASTE_END, "\033[201~", 0 },
/* Function keys. */
{ KEYC_F1, "\033OP", 0 },
{ KEYC_F2, "\033OQ", 0 },
@@ -172,7 +176,7 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
* If this is a normal 7-bit key, just send it, with a leading escape
* if necessary. If it is a UTF-8 key, split it and send it.
*/
justkey = (key & ~KEYC_ESCAPE);
justkey = (key & ~(KEYC_XTERM|KEYC_ESCAPE));
if (justkey <= 0x7f) {
if (key & KEYC_ESCAPE)
bufferevent_write(wp->event, "\033", 1);
@@ -200,6 +204,7 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
return;
}
}
key &= ~KEYC_XTERM;
/* Otherwise look the key up in the table. */
for (i = 0; i < nitems(input_keys); i++) {
@@ -242,10 +247,10 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m)
if ((mode & ALL_MOUSE_MODES) == 0)
return;
if (!window_pane_visible(wp))
return;
if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
return;
if (!window_pane_visible(wp))
return;
/* If this pane is not in button or all mode, discard motion events. */
if (MOUSE_DRAG(m->b) &&

952
input.c

File diff suppressed because it is too large Load Diff

172
job.c
View File

@@ -32,35 +32,73 @@
* output.
*/
static void job_callback(struct bufferevent *, short, void *);
static void job_read_callback(struct bufferevent *, void *);
static void job_write_callback(struct bufferevent *, void *);
static void job_error_callback(struct bufferevent *, short, void *);
/* A single job. */
struct job {
enum {
JOB_RUNNING,
JOB_DEAD,
JOB_CLOSED
} state;
int flags;
char *cmd;
pid_t pid;
int status;
int fd;
struct bufferevent *event;
job_update_cb updatecb;
job_complete_cb completecb;
job_free_cb freecb;
void *data;
LIST_ENTRY(job) entry;
};
/* All jobs list. */
struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
static LIST_HEAD(joblist, job) all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
/* Start a job running, if it isn't already. */
struct job *
job_run(const char *cmd, struct session *s, const char *cwd,
void (*callbackfn)(struct job *), void (*freefn)(void *), void *data)
job_update_cb updatecb, job_complete_cb completecb, job_free_cb freecb,
void *data, int flags)
{
struct job *job;
struct environ *env;
pid_t pid;
int nullfd, out[2];
const char *home;
sigset_t set, oldset;
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0)
return (NULL);
log_debug("%s: cmd=%s, cwd=%s", __func__, cmd, cwd == NULL ? "" : cwd);
env = environ_for_session(s);
/*
* Do not set TERM during .tmux.conf, it is nice to be able to use
* if-shell to decide on default-terminal based on outside TERM.
*/
env = environ_for_session(s, !cfg_finished);
sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, &oldset);
switch (pid = fork()) {
case -1:
sigprocmask(SIG_SETMASK, &oldset, NULL);
environ_free(env);
close(out[0]);
close(out[1]);
return (NULL);
case 0: /* child */
clear_signals(1);
case 0:
proc_clear_signals(server_proc, 1);
sigprocmask(SIG_SETMASK, &oldset, NULL);
if (cwd == NULL || chdir(cwd) != 0) {
if ((home = find_home()) == NULL || chdir(home) != 0)
@@ -92,28 +130,32 @@ job_run(const char *cmd, struct session *s, const char *cwd,
fatal("execl failed");
}
/* parent */
sigprocmask(SIG_SETMASK, &oldset, NULL);
environ_free(env);
close(out[1]);
job = xmalloc(sizeof *job);
job->state = JOB_RUNNING;
job->flags = flags;
job->cmd = xstrdup(cmd);
job->pid = pid;
job->status = 0;
LIST_INSERT_HEAD(&all_jobs, job, lentry);
LIST_INSERT_HEAD(&all_jobs, job, entry);
job->callbackfn = callbackfn;
job->freefn = freefn;
job->updatecb = updatecb;
job->completecb = completecb;
job->freecb = freecb;
job->data = data;
job->fd = out[0];
setblocking(job->fd, 0);
job->event = bufferevent_new(job->fd, NULL, job_write_callback,
job_callback, job);
job->event = bufferevent_new(job->fd, job_read_callback,
job_write_callback, job_error_callback, job);
if (job->event == NULL)
fatalx("out of memory");
bufferevent_enable(job->event, EV_READ|EV_WRITE);
log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid);
@@ -126,11 +168,11 @@ job_free(struct job *job)
{
log_debug("free job %p: %s", job, job->cmd);
LIST_REMOVE(job, lentry);
LIST_REMOVE(job, entry);
free(job->cmd);
if (job->freefn != NULL && job->data != NULL)
job->freefn(job->data);
if (job->freecb != NULL && job->data != NULL)
job->freecb(job->data);
if (job->pid != -1)
kill(job->pid, SIGTERM);
@@ -142,7 +184,21 @@ job_free(struct job *job)
free(job);
}
/* Called when output buffer falls below low watermark (default is 0). */
/* Job buffer read callback. */
static void
job_read_callback(__unused struct bufferevent *bufev, void *data)
{
struct job *job = data;
if (job->updatecb != NULL)
job->updatecb(job);
}
/*
* Job buffer write callback. Fired when the buffer falls below watermark
* (default is empty). If all the data has been written, disable the write
* event.
*/
static void
job_write_callback(__unused struct bufferevent *bufev, void *data)
{
@@ -160,7 +216,7 @@ job_write_callback(__unused struct bufferevent *bufev, void *data)
/* Job buffer error callback. */
static void
job_callback(__unused struct bufferevent *bufev, __unused short events,
job_error_callback(__unused struct bufferevent *bufev, __unused short events,
void *data)
{
struct job *job = data;
@@ -168,8 +224,8 @@ job_callback(__unused struct bufferevent *bufev, __unused short events,
log_debug("job error %p: %s, pid %ld", job, job->cmd, (long) job->pid);
if (job->state == JOB_DEAD) {
if (job->callbackfn != NULL)
job->callbackfn(job);
if (job->completecb != NULL)
job->completecb(job);
job_free(job);
} else {
bufferevent_disable(job->event, EV_READ);
@@ -179,18 +235,90 @@ job_callback(__unused struct bufferevent *bufev, __unused short events,
/* Job died (waitpid() returned its pid). */
void
job_died(struct job *job, int status)
job_check_died(pid_t pid, int status)
{
struct job *job;
LIST_FOREACH(job, &all_jobs, entry) {
if (pid == job->pid)
break;
}
if (job == NULL)
return;
log_debug("job died %p: %s, pid %ld", job, job->cmd, (long) job->pid);
job->status = status;
if (job->state == JOB_CLOSED) {
if (job->callbackfn != NULL)
job->callbackfn(job);
if (job->completecb != NULL)
job->completecb(job);
job_free(job);
} else {
job->pid = -1;
job->state = JOB_DEAD;
}
}
/* Get job status. */
int
job_get_status(struct job *job)
{
return (job->status);
}
/* Get job data. */
void *
job_get_data(struct job *job)
{
return (job->data);
}
/* Get job event. */
struct bufferevent *
job_get_event(struct job *job)
{
return (job->event);
}
/* Kill all jobs. */
void
job_kill_all(void)
{
struct job *job;
LIST_FOREACH(job, &all_jobs, entry) {
if (job->pid != -1)
kill(job->pid, SIGTERM);
}
}
/* Are any jobs still running? */
int
job_still_running(void)
{
struct job *job;
LIST_FOREACH(job, &all_jobs, entry) {
if ((~job->flags & JOB_NOWAIT) && job->state == JOB_RUNNING)
return (1);
}
return (0);
}
/* Print job summary. */
void
job_print_summary(struct cmdq_item *item, int blank)
{
struct job *job;
u_int n = 0;
LIST_FOREACH(job, &all_jobs, entry) {
if (blank) {
cmdq_print(item, "%s", "");
blank = 0;
}
cmdq_print(item, "Job %u: %s [fd=%d, pid=%ld, status=%d]",
n, job->cmd, job->fd, (long)job->pid, job->status);
n++;
}
}

View File

@@ -24,17 +24,19 @@
#include "tmux.h"
RB_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp);
RB_GENERATE(key_tables, key_table, entry, key_table_cmp);
struct key_tables key_tables = RB_INITIALIZER(&key_tables);
static int key_bindings_cmp(struct key_binding *, struct key_binding *);
RB_GENERATE_STATIC(key_bindings, key_binding, entry, key_bindings_cmp);
static int key_table_cmp(struct key_table *, struct key_table *);
RB_GENERATE_STATIC(key_tables, key_table, entry, key_table_cmp);
static struct key_tables key_tables = RB_INITIALIZER(&key_tables);
int
key_table_cmp(struct key_table *e1, struct key_table *e2)
static int
key_table_cmp(struct key_table *table1, struct key_table *table2)
{
return (strcmp(e1->name, e2->name));
return (strcmp(table1->name, table2->name));
}
int
static int
key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2)
{
if (bd1->key < bd2->key)
@@ -64,6 +66,18 @@ key_bindings_get_table(const char *name, int create)
return (table);
}
struct key_table *
key_bindings_first_table(void)
{
return (RB_MIN(key_tables, &key_tables));
}
struct key_table *
key_bindings_next_table(struct key_table *table)
{
return (RB_NEXT(key_tables, &key_tables, table));
}
void
key_bindings_unref_table(struct key_table *table)
{
@@ -83,8 +97,29 @@ key_bindings_unref_table(struct key_table *table)
free(table);
}
struct key_binding *
key_bindings_get(struct key_table *table, key_code key)
{
struct key_binding bd;
bd.key = key;
return (RB_FIND(key_bindings, &table->key_bindings, &bd));
}
struct key_binding *
key_bindings_first(struct key_table *table)
{
return (RB_MIN(key_bindings, &table->key_bindings));
}
struct key_binding *
key_bindings_next(__unused struct key_table *table, struct key_binding *bd)
{
return (RB_NEXT(key_bindings, &table->key_bindings, bd));
}
void
key_bindings_add(const char *name, key_code key, int can_repeat,
key_bindings_add(const char *name, key_code key, int repeat,
struct cmd_list *cmdlist)
{
struct key_table *table;
@@ -92,7 +127,7 @@ key_bindings_add(const char *name, key_code key, int can_repeat,
table = key_bindings_get_table(name, 1);
bd_find.key = key;
bd_find.key = (key & ~KEYC_XTERM);
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
if (bd != NULL) {
RB_REMOVE(key_bindings, &table->key_bindings, bd);
@@ -100,11 +135,12 @@ key_bindings_add(const char *name, key_code key, int can_repeat,
free(bd);
}
bd = xmalloc(sizeof *bd);
bd = xcalloc(1, sizeof *bd);
bd->key = key;
RB_INSERT(key_bindings, &table->key_bindings, bd);
bd->can_repeat = can_repeat;
if (repeat)
bd->flags |= KEY_BINDING_REPEAT;
bd->cmdlist = cmdlist;
}
@@ -118,7 +154,7 @@ key_bindings_remove(const char *name, key_code key)
if (table == NULL)
return;
bd_find.key = key;
bd_find.key = (key & ~KEYC_XTERM);
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
if (bd == NULL)
return;
@@ -137,12 +173,17 @@ void
key_bindings_remove_table(const char *name)
{
struct key_table *table;
struct client *c;
table = key_bindings_get_table(name, 0);
if (table != NULL) {
RB_REMOVE(key_tables, &key_tables, table);
key_bindings_unref_table(table);
}
TAILQ_FOREACH(c, &clients, entry) {
if (c->keytable == table)
server_client_set_key_table(c, NULL);
}
}
void
@@ -156,13 +197,13 @@ key_bindings_init(void)
"bind ! break-pane",
"bind '\"' split-window",
"bind '#' list-buffers",
"bind '$' command-prompt -I'#S' \"rename-session '%%'\"",
"bind '$' command-prompt -I'#S' \"rename-session -- '%%'\"",
"bind % split-window -h",
"bind & confirm-before -p\"kill-window #W? (y/n)\" kill-window",
"bind \"'\" command-prompt -pindex \"select-window -t ':%%'\"",
"bind ( switch-client -p",
"bind ) switch-client -n",
"bind , command-prompt -I'#W' \"rename-window '%%'\"",
"bind , command-prompt -I'#W' \"rename-window -- '%%'\"",
"bind - delete-buffer",
"bind . command-prompt \"move-window -t '%%'\"",
"bind 0 select-window -t:=0",
@@ -177,16 +218,17 @@ key_bindings_init(void)
"bind 9 select-window -t:=9",
"bind : command-prompt",
"bind \\; last-pane",
"bind = choose-buffer",
"bind = choose-buffer -Z",
"bind ? list-keys",
"bind D choose-client",
"bind D choose-client -Z",
"bind E select-layout -E",
"bind L switch-client -l",
"bind M select-pane -M",
"bind [ copy-mode",
"bind ] paste-buffer",
"bind c new-window",
"bind d detach-client",
"bind f command-prompt \"find-window '%%'\"",
"bind f command-prompt \"find-window -Z -- '%%'\"",
"bind i display-message",
"bind l last-window",
"bind m select-pane -m",
@@ -195,9 +237,9 @@ key_bindings_init(void)
"bind p previous-window",
"bind q display-panes",
"bind r refresh-client",
"bind s choose-tree",
"bind s choose-tree -Zs",
"bind t clock-mode",
"bind w choose-window",
"bind w choose-tree -Zw",
"bind x confirm-before -p\"kill-pane #P? (y/n)\" kill-pane",
"bind z resize-pane -Z",
"bind { swap-pane -U",
@@ -216,6 +258,11 @@ key_bindings_init(void)
"bind M-n next-window -a",
"bind M-o rotate-window -D",
"bind M-p previous-window -a",
"bind -r S-Up refresh-client -U 10",
"bind -r S-Down refresh-client -D 10",
"bind -r S-Left refresh-client -L 10",
"bind -r S-Right refresh-client -R 10",
"bind -r DC refresh-client -c",
"bind -r M-Up resize-pane -U 5",
"bind -r M-Down resize-pane -D 5",
"bind -r M-Left resize-pane -L 5",
@@ -243,23 +290,23 @@ key_bindings_init(void)
"bind -Tcopy-mode C-k send -X copy-end-of-line",
"bind -Tcopy-mode C-n send -X cursor-down",
"bind -Tcopy-mode C-p send -X cursor-up",
"bind -Tcopy-mode C-r command-prompt -ip'search up' 'send -X search-backward-incremental \"%%%\"'",
"bind -Tcopy-mode C-s command-prompt -ip'search down' 'send -X search-forward-incremental \"%%%\"'",
"bind -Tcopy-mode C-r command-prompt -ip'(search up)' -I'#{pane_search_string}' 'send -X search-backward-incremental \"%%%\"'",
"bind -Tcopy-mode C-s command-prompt -ip'(search down)' -I'#{pane_search_string}' 'send -X search-forward-incremental \"%%%\"'",
"bind -Tcopy-mode C-v send -X page-down",
"bind -Tcopy-mode C-w send -X copy-selection-and-cancel",
"bind -Tcopy-mode Escape send -X cancel",
"bind -Tcopy-mode Space send -X page-down",
"bind -Tcopy-mode , send -X jump-reverse",
"bind -Tcopy-mode \\; send -X jump-again",
"bind -Tcopy-mode F command-prompt -1p'jump backward' 'send -X jump-backward \"%%%\"'",
"bind -Tcopy-mode F command-prompt -1p'(jump backward)' 'send -X jump-backward \"%%%\"'",
"bind -Tcopy-mode N send -X search-reverse",
"bind -Tcopy-mode R send -X rectangle-toggle",
"bind -Tcopy-mode T command-prompt -1p'jump to backward' 'send -X jump-to-backward \"%%%\"'",
"bind -Tcopy-mode f command-prompt -1p'jump forward' 'send -X jump-forward \"%%%\"'",
"bind -Tcopy-mode g command-prompt -p'goto line' 'send -X goto-line \"%%%\"'",
"bind -Tcopy-mode T command-prompt -1p'(jump to backward)' 'send -X jump-to-backward \"%%%\"'",
"bind -Tcopy-mode f command-prompt -1p'(jump forward)' 'send -X jump-forward \"%%%\"'",
"bind -Tcopy-mode g command-prompt -p'(goto line)' 'send -X goto-line \"%%%\"'",
"bind -Tcopy-mode n send -X search-again",
"bind -Tcopy-mode q send -X cancel",
"bind -Tcopy-mode t command-prompt -1p'jump to forward' 'send -X jump-to-forward \"%%%\"'",
"bind -Tcopy-mode t command-prompt -1p'(jump to forward)' 'send -X jump-to-forward \"%%%\"'",
"bind -Tcopy-mode Home send -X start-of-line",
"bind -Tcopy-mode End send -X end-of-line",
"bind -Tcopy-mode MouseDown1Pane select-pane",
@@ -275,15 +322,15 @@ key_bindings_init(void)
"bind -Tcopy-mode Down send -X cursor-down",
"bind -Tcopy-mode Left send -X cursor-left",
"bind -Tcopy-mode Right send -X cursor-right",
"bind -Tcopy-mode M-1 command-prompt -Np'repeat' -I1 'send -N \"%%%\"'",
"bind -Tcopy-mode M-2 command-prompt -Np'repeat' -I2 'send -N \"%%%\"'",
"bind -Tcopy-mode M-3 command-prompt -Np'repeat' -I3 'send -N \"%%%\"'",
"bind -Tcopy-mode M-4 command-prompt -Np'repeat' -I4 'send -N \"%%%\"'",
"bind -Tcopy-mode M-5 command-prompt -Np'repeat' -I5 'send -N \"%%%\"'",
"bind -Tcopy-mode M-6 command-prompt -Np'repeat' -I6 'send -N \"%%%\"'",
"bind -Tcopy-mode M-7 command-prompt -Np'repeat' -I7 'send -N \"%%%\"'",
"bind -Tcopy-mode M-8 command-prompt -Np'repeat' -I8 'send -N \"%%%\"'",
"bind -Tcopy-mode M-9 command-prompt -Np'repeat' -I9 'send -N \"%%%\"'",
"bind -Tcopy-mode M-1 command-prompt -Np'(repeat)' -I1 'send -N \"%%%\"'",
"bind -Tcopy-mode M-2 command-prompt -Np'(repeat)' -I2 'send -N \"%%%\"'",
"bind -Tcopy-mode M-3 command-prompt -Np'(repeat)' -I3 'send -N \"%%%\"'",
"bind -Tcopy-mode M-4 command-prompt -Np'(repeat)' -I4 'send -N \"%%%\"'",
"bind -Tcopy-mode M-5 command-prompt -Np'(repeat)' -I5 'send -N \"%%%\"'",
"bind -Tcopy-mode M-6 command-prompt -Np'(repeat)' -I6 'send -N \"%%%\"'",
"bind -Tcopy-mode M-7 command-prompt -Np'(repeat)' -I7 'send -N \"%%%\"'",
"bind -Tcopy-mode M-8 command-prompt -Np'(repeat)' -I8 'send -N \"%%%\"'",
"bind -Tcopy-mode M-9 command-prompt -Np'(repeat)' -I9 'send -N \"%%%\"'",
"bind -Tcopy-mode M-< send -X history-top",
"bind -Tcopy-mode M-> send -X history-bottom",
"bind -Tcopy-mode M-R send -X top-line",
@@ -315,25 +362,25 @@ key_bindings_init(void)
"bind -Tcopy-mode-vi Space send -X begin-selection",
"bind -Tcopy-mode-vi '$' send -X end-of-line",
"bind -Tcopy-mode-vi , send -X jump-reverse",
"bind -Tcopy-mode-vi / command-prompt -p'search down' 'send -X search-forward \"%%%\"'",
"bind -Tcopy-mode-vi / command-prompt -p'(search down)' 'send -X search-forward \"%%%\"'",
"bind -Tcopy-mode-vi 0 send -X start-of-line",
"bind -Tcopy-mode-vi 1 command-prompt -Np'repeat' -I1 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 2 command-prompt -Np'repeat' -I2 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 3 command-prompt -Np'repeat' -I3 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 4 command-prompt -Np'repeat' -I4 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 5 command-prompt -Np'repeat' -I5 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 6 command-prompt -Np'repeat' -I6 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 7 command-prompt -Np'repeat' -I7 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 8 command-prompt -Np'repeat' -I8 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 9 command-prompt -Np'repeat' -I9 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi : command-prompt -p'goto line' 'send -X goto-line \"%%%\"'",
"bind -Tcopy-mode-vi 1 command-prompt -Np'(repeat)' -I1 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 2 command-prompt -Np'(repeat)' -I2 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 3 command-prompt -Np'(repeat)' -I3 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 4 command-prompt -Np'(repeat)' -I4 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 5 command-prompt -Np'(repeat)' -I5 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 6 command-prompt -Np'(repeat)' -I6 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 7 command-prompt -Np'(repeat)' -I7 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 8 command-prompt -Np'(repeat)' -I8 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi 9 command-prompt -Np'(repeat)' -I9 'send -N \"%%%\"'",
"bind -Tcopy-mode-vi : command-prompt -p'(goto line)' 'send -X goto-line \"%%%\"'",
"bind -Tcopy-mode-vi \\; send -X jump-again",
"bind -Tcopy-mode-vi ? command-prompt -p'search up' 'send -X search-backward \"%%%\"'",
"bind -Tcopy-mode-vi ? command-prompt -p'(search up)' 'send -X search-backward \"%%%\"'",
"bind -Tcopy-mode-vi A send -X append-selection-and-cancel",
"bind -Tcopy-mode-vi B send -X previous-space",
"bind -Tcopy-mode-vi D send -X copy-end-of-line",
"bind -Tcopy-mode-vi E send -X next-space-end",
"bind -Tcopy-mode-vi F command-prompt -1p'jump backward' 'send -X jump-backward \"%%%\"'",
"bind -Tcopy-mode-vi F command-prompt -1p'(jump backward)' 'send -X jump-backward \"%%%\"'",
"bind -Tcopy-mode-vi G send -X history-bottom",
"bind -Tcopy-mode-vi H send -X top-line",
"bind -Tcopy-mode-vi J send -X scroll-down",
@@ -341,13 +388,13 @@ key_bindings_init(void)
"bind -Tcopy-mode-vi L send -X bottom-line",
"bind -Tcopy-mode-vi M send -X middle-line",
"bind -Tcopy-mode-vi N send -X search-reverse",
"bind -Tcopy-mode-vi T command-prompt -1p'jump to backward' 'send -X jump-to-backward \"%%%\"'",
"bind -Tcopy-mode-vi T command-prompt -1p'(jump to backward)' 'send -X jump-to-backward \"%%%\"'",
"bind -Tcopy-mode-vi V send -X select-line",
"bind -Tcopy-mode-vi W send -X next-space",
"bind -Tcopy-mode-vi ^ send -X back-to-indentation",
"bind -Tcopy-mode-vi b send -X previous-word",
"bind -Tcopy-mode-vi e send -X next-word-end",
"bind -Tcopy-mode-vi f command-prompt -1p'jump forward' 'send -X jump-forward \"%%%\"'",
"bind -Tcopy-mode-vi f command-prompt -1p'(jump forward)' 'send -X jump-forward \"%%%\"'",
"bind -Tcopy-mode-vi g send -X history-top",
"bind -Tcopy-mode-vi h send -X cursor-left",
"bind -Tcopy-mode-vi j send -X cursor-down",
@@ -356,7 +403,7 @@ key_bindings_init(void)
"bind -Tcopy-mode-vi n send -X search-again",
"bind -Tcopy-mode-vi o send -X other-end",
"bind -Tcopy-mode-vi q send -X cancel",
"bind -Tcopy-mode-vi t command-prompt -1p'jump to forward' 'send -X jump-to-forward \"%%%\"'",
"bind -Tcopy-mode-vi t command-prompt -1p'(jump to forward)' 'send -X jump-to-forward \"%%%\"'",
"bind -Tcopy-mode-vi v send -X rectangle-toggle",
"bind -Tcopy-mode-vi w send -X next-word",
"bind -Tcopy-mode-vi { send -X previous-paragraph",
@@ -399,11 +446,11 @@ key_bindings_read_only(struct cmdq_item *item, __unused void *data)
}
void
key_bindings_dispatch(struct key_binding *bd, struct client *c,
struct mouse_event *m, struct cmd_find_state *fs)
key_bindings_dispatch(struct key_binding *bd, struct cmdq_item *item,
struct client *c, struct mouse_event *m, struct cmd_find_state *fs)
{
struct cmd *cmd;
struct cmdq_item *item;
struct cmdq_item *new_item;
int readonly;
readonly = 1;
@@ -412,10 +459,14 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c,
readonly = 0;
}
if (!readonly && (c->flags & CLIENT_READONLY))
cmdq_append(c, cmdq_get_callback(key_bindings_read_only, NULL));
new_item = cmdq_get_callback(key_bindings_read_only, NULL);
else {
item = cmdq_get_command(bd->cmdlist, fs, m, 0);
item->repeat = bd->can_repeat;
cmdq_append(c, item);
new_item = cmdq_get_command(bd->cmdlist, fs, m, 0);
if (bd->flags & KEY_BINDING_REPEAT)
new_item->shared->flags |= CMDQ_SHARED_REPEAT;
}
if (item != NULL)
cmdq_insert_after(item, new_item);
else
cmdq_append(c, new_item);
}

View File

@@ -43,7 +43,9 @@ static const struct {
{ "F11", KEYC_F11 },
{ "F12", KEYC_F12 },
{ "IC", KEYC_IC },
{ "Insert", KEYC_IC },
{ "DC", KEYC_DC },
{ "Delete", KEYC_DC },
{ "Home", KEYC_HOME },
{ "End", KEYC_END },
{ "NPage", KEYC_NPAGE },
@@ -110,12 +112,16 @@ static const struct {
static key_code
key_string_search_table(const char *string)
{
u_int i;
u_int i, user;
for (i = 0; i < nitems(key_string_table); i++) {
if (strcasecmp(string, key_string_table[i].string) == 0)
return (key_string_table[i].key);
}
if (sscanf(string, "User%u", &user) == 1 && user < KEYC_NUSER)
return (KEYC_USER + user);
return (KEYC_UNKNOWN);
}
@@ -162,9 +168,11 @@ key_string_lookup_string(const char *string)
enum utf8_state more;
wchar_t wc;
/* Is this no key? */
/* Is this no key or any key? */
if (strcasecmp(string, "None") == 0)
return (KEYC_NONE);
if (strcasecmp(string, "Any") == 0)
return (KEYC_ANY);
/* Is this a hexadecimal value? */
if (string[0] == '0' && string[1] == 'x') {
@@ -247,10 +255,16 @@ key_string_lookup_key(key_code key)
/* Handle special keys. */
if (key == KEYC_UNKNOWN)
return ("Unknown");
if (key == KEYC_ANY)
return ("Any");
if (key == KEYC_FOCUS_IN)
return ("FocusIn");
if (key == KEYC_FOCUS_OUT)
return ("FocusOut");
if (key == KEYC_PASTE_START)
return ("PasteStart");
if (key == KEYC_PASTE_END)
return ("PasteEnd");
if (key == KEYC_MOUSE)
return ("Mouse");
if (key == KEYC_DRAGGING)
@@ -259,8 +273,16 @@ key_string_lookup_key(key_code key)
return ("MouseMovePane");
if (key == KEYC_MOUSEMOVE_STATUS)
return ("MouseMoveStatus");
if (key == KEYC_MOUSEMOVE_STATUS_LEFT)
return ("MouseMoveStatusLeft");
if (key == KEYC_MOUSEMOVE_STATUS_RIGHT)
return ("MouseMoveStatusRight");
if (key == KEYC_MOUSEMOVE_BORDER)
return ("MouseMoveBorder");
if (key >= KEYC_USER && key < KEYC_USER + KEYC_NUSER) {
snprintf(out, sizeof out, "User%u", (u_int)(key - KEYC_USER));
return (out);
}
/*
* Special case: display C-@ as C-Space. Could do this below in

View File

@@ -167,7 +167,7 @@ layout_parse(struct window *w, const char *layout)
/* Update pane offsets and sizes. */
layout_fix_offsets(lc);
layout_fix_panes(w, lc->sx, lc->sy);
layout_fix_panes(w);
/* Then resize the layout back to the original window size. */
layout_resize(w, sx, sy);

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