148 Commits
2.2 ... 2.3

Author SHA1 Message Date
Thomas Adam
52869ed182 Release tmux 2.3 2016-09-29 21:54:12 +01:00
Thomas Adam
19104d592b Merge branch 'obsd-master' 2016-09-29 12:01:11 +01:00
nicm
cf7f3a436a Check padding when writing any character with width > 1, in case they
overlap after the first character (for example with cells xy and ab, y
is replacing a).
2016-09-29 08:50:43 +00:00
Thomas Adam
c41916ee16 Merge branch 'obsd-master' 2016-09-28 18:01:11 +01:00
nicm
bb5798aa0e Couple of vasprintf -> xvasprintf. 2016-09-28 14:40:07 +00:00
Thomas Adam
27591570c4 Merge branch 'obsd-master' 2016-09-28 10:01:11 +01:00
nicm
acacb718e5 Rate limit TIOCSWINSZ on a timer to avoid programs getting hammered with
SIGWINCH when the size changes rapidly. To help a problem reported by
Rui Pinheiro.
2016-09-28 08:30:44 +00:00
Thomas Adam
30f2e8ff29 Merge branch 'obsd-master' 2016-09-26 12:01:12 +01:00
nicm
69e980602b Support set -a (append) with user options, suggested by Xandor Schiefer. 2016-09-26 09:02:34 +00:00
Nicholas Marriott
cbde98f67b Merge branch 'master' of github.com:tmux/tmux 2016-09-16 18:09:51 +01:00
Thomas Adam
895f1d93d5 Merge branch 'obsd-master' 2016-09-16 16:01:16 +01:00
nicm
eb50e7a2c8 Swap watermarks from high (4096) to low (128) when we get full buffers
into the read callback several times in succession; swap back when we
see empty buffers several times. This hopefully limits how much programs
that print a lot for a long period can monopolize tmux (like large, fast
compiling), without penalizing programs that print a lot briefly (like
most curses applications). Helps a lot for me, the actual numbers may
need tweaking later.
2016-09-16 13:43:41 +00:00
Nicholas Marriott
6e8f400edc Do not use utf8proc by default. 2016-09-15 20:37:48 +01:00
Thomas Adam
a5b29a1250 Merge branch 'obsd-master' 2016-09-12 18:01:12 +01:00
nicm
2e5584c2b4 Allow repeat count to be specified in mode key tables with bind-key -R,
and set the default repeat count to 5 for WheelUp and WheelDown in
copy-mode.
2016-09-12 15:40:58 +00:00
Nicholas Marriott
060515684d Apple have changed their API again, from Gregory Pakosz. 2016-09-12 11:06:35 +01:00
Nicholas Marriott
c6cdab1f79 Use ncurses OR curses, don't mix header and library. Tested by Rob Paisley. 2016-09-08 19:28:56 +01:00
Nicholas Marriott
3ed0973493 Solaris build fixes from Rob Paisley. 2016-09-08 15:32:15 +01:00
Thomas Adam
f68a908c8a Merge branch 'obsd-master' 2016-09-04 20:01:16 +01:00
nicm
fed1e384ad Add support for performing a full width split (with splitw -f), rather
than splitting the current cell. From Stephen Kent.
2016-09-04 17:37:06 +00:00
Thomas Adam
999c1c771b Merge branch 'obsd-master' 2016-09-03 00:01:14 +01:00
Nicholas Marriott
727ce7e4bb Check for headers for ncurses and libevent as well as libraries. 2016-09-02 22:05:06 +01:00
nicm
2627ab322e Remember the number of lines scrolled into the history (versus cleared
into the history) and when resizing only use scrolled lines and not
cleared lines (which are probably not intended to reappear). From
Chaoren Lin.
2016-09-02 20:57:20 +00:00
Nicholas Marriott
6c94774b70 Add support for using utf8proc with --enable-utf8proc, useful for platforms
(like OS X) where the system implementation is crap. From Joshua Rubin.
2016-09-01 20:40:03 +01:00
Thomas Adam
ae297cb487 Merge branch 'obsd-master' 2016-08-28 02:01:11 +01:00
nicm
537964b92d Kill empty window after moving pane and updating current window, so that
index is still valid before renumber-windows happens. Fixes issue
reported by Eric Pruitt.
2016-08-27 23:35:00 +00:00
Thomas Adam
1bc467fe52 Merge branch 'obsd-master' 2016-08-25 12:01:10 +01:00
nicm
6bf033beae Do not crash if display-message used without a client, issue reported by
Serge Aleynikov, fix from Thomas Adam.
2016-08-25 09:33:14 +00:00
Thomas Adam
88eb302221 Merge branch 'obsd-master' 2016-08-22 22:01:13 +01:00
nicm
43f292b2e0 Two minor fixes from dilyan palauzov. 2016-08-22 20:07:58 +00:00
Thomas Adam
baf1550227 Merge branch 'obsd-master' 2016-08-03 12:01:11 +01:00
nicm
f811127bb6 We only replace the first %%, not multiple (use %2 for second). 2016-08-03 09:08:40 +00:00
nicm
f8cc48a43f Fix minimum size when pane status line is enabled, reported by Y Petremann. 2016-08-03 09:07:02 +00:00
Nicholas Marriott
af38936473 Merge branch 'master' of github.com:tmux/tmux 2016-07-19 10:43:10 +01:00
Nicholas Marriott
0e11036055 Add to .mailmap. 2016-07-19 10:42:44 +01:00
Thomas Adam
a24260bb23 Merge branch 'obsd-master' 2016-07-15 12:01:10 +01:00
nicm
9436a31603 Tweak output of environment logging. 2016-07-15 09:52:34 +00:00
nicm
1718420c48 Log environment to new panes. 2016-07-15 09:28:32 +00:00
nicm
68b1fd0cc6 Wrap some long lines and apply some static. 2016-07-15 09:27:35 +00:00
Thomas Adam
d4eeeb5498 Merge branch 'obsd-master' 2016-07-15 04:01:12 +01:00
nicm
0f73af876f Don't update cells in each block of data read from a pane immediately,
instead track them as change (dirty) and update them once at the end,
saves much time if repeatedly writing the same cell. Also fix comparison
of cells being equal in a few places (memcmp is not enough).
2016-07-15 00:49:08 +00:00
nicm
1fd6ca2260 Instead of representing colours in several different forms with various
cell flags, convert to use an int with flags marking 256 or RGB colours
in the top byte (except in cells, which we don't want to make any
bigger). From Brad Town.
2016-07-15 00:42:56 +00:00
Thomas Adam
2d843b5021 Merge branch 'obsd-master' 2016-07-07 12:01:11 +01:00
semarie
fc118e13a9 tmux: only consider ACCESSPERMS for setting mode on socket_path.
it explicitly removes any S_ISUID|S_ISGID|S_ISTXT bits, instead of letting
pledge(2) silenciously remove them.

ok nicm@ beck@ deraadt@
2016-07-07 09:24:09 +00:00
Nicholas Marriott
25e128d398 Remove duplicate daemon.c and time.h. 2016-06-27 10:57:02 +01:00
Thomas Adam
93f42d360b Merge branch 'obsd-master' 2016-06-16 14:01:11 +01:00
nicm
325cbe90d9 Allow a command to be specified to display-panes, similar to
command-prompt, rather than always just selecting the pane.
2016-06-16 10:55:47 +00:00
Thomas Adam
d35a9ac5f2 Linux: <time.h> 2016-06-16 11:43:05 +01:00
Thomas Adam
1ad7c6b8f8 Merge branch 'obsd-master' 2016-06-15 18:01:11 +01:00
nicm
0c7ddae2ab Add missing buffer_name format, from Awal Garg. 2016-06-15 14:43:06 +00:00
Thomas Adam
5c12230a08 Merge branch 'obsd-master' 2016-06-15 12:01:11 +01:00
nicm
bee3e3e28d Copy mode needs to keep the original grid intact so it can copy from it
if needed, so it disables reading from the pane. This can be problem
with some programs. So make tmux automatically exit all modes after 180
seconds of inactivity and if there is pending output.
2016-06-15 09:13:46 +00:00
nicm
068b8b03ad Add -F to list-commands. 2016-06-15 08:54:11 +00:00
Nicholas Marriott
150c9f3fe0 Add *.dSYM for OS X. 2016-06-15 09:51:08 +01:00
Nicholas Marriott
697b912f26 Merge branch 'master' of github.com:tmux/tmux 2016-06-10 16:38:52 +01:00
Nicholas Marriott
b9c95937ed Add to TODO. 2016-06-10 16:38:40 +01:00
Thomas Adam
1a53e79057 Merge branch 'obsd-master' 2016-06-10 14:01:10 +01:00
Nicholas Marriott
c84ed36719 Spelling, from Josh Soref. 2016-06-10 12:47:15 +01:00
nicm
17e4744459 Spelling error (incrased -> increased), from Josh Soref. 2016-06-10 11:46:15 +00:00
Thomas Adam
fa68d0a16e Merge branch 'obsd-master' 2016-06-06 12:01:10 +01:00
nicm
d9450bfccd Much faster (and smaller) method of mapping RGB colour to an xterm(1)
colour, from Avi Halachmi.
2016-06-06 10:12:58 +00:00
Thomas Adam
cc096ae929 Merge branch 'obsd-master' 2016-06-06 10:01:11 +01:00
Nicholas Marriott
1f75c98f49 Note how to subscribe to ML. 2016-06-06 09:30:39 +01:00
nicm
aba4438013 Cache selected state so that cells going from selected to unselected are not
skipped, reported by Omar Sandoval.
2016-06-06 07:28:52 +00:00
nicm
00cf5fbde6 Insert new panes after the pane being split in the list rather than
always after the active pane. This is more sensible when doing it with
commands rather than keys.
2016-06-06 07:24:31 +00:00
nicm
3c10df4f87 Allow #[] in window-status-separator. 2016-06-06 07:23:36 +00:00
Nicholas Marriott
89c17e44fb Updated link for bash(1) completions. 2016-06-01 00:06:02 +01:00
Nicholas Marriott
20d2a31b40 Update TODO. 2016-05-31 22:13:44 +01:00
Thomas Adam
c7a0f56c71 Merge branch 'obsd-master' 2016-05-30 12:01:13 +01:00
nicm
1921fac814 Cache the window styles and do not look up the window-style options
unless they have changed.
2016-05-30 09:50:20 +00:00
nicm
36ab4c7c49 Do not draw character to screen if it has not changed, and do not save
last character if it won't be used. This (and last few commits) prompted
by a report from Hubert depesz Lubaczewski.
2016-05-30 09:32:24 +00:00
nicm
7d105738b6 Send two cub1 instead of using cub for moving the cursor two left. This
is normally better because using cub1 will be ^H^H (so two bytes) but
cub would be ^[[2D (four).
2016-05-30 09:26:49 +00:00
Nicholas Marriott
5e9412608e No longer set __progname, we have getprogname(). 2016-05-30 10:02:08 +01:00
Thomas Adam
7a2fed494b Merge branch 'obsd-master' 2016-05-28 02:01:10 +01:00
nicm
344a6a6202 Padding cell is always the same so use a static. 2016-05-27 23:06:12 +00:00
nicm
382222af8e Break the save-last-cell code into a separate function (so it can be
called conditionally later).
2016-05-27 23:02:17 +00:00
nicm
9892d80d6f Most of the utf8_data is fixed so simplify utf8_set to use a memcpy. 2016-05-27 22:57:27 +00:00
Thomas Adam
c10d83b4df __progname -> getprogname()
Fix fallout from recent use of getprogname(), which deprecates __progname.
2016-05-27 20:11:32 +01:00
Thomas Adam
a2e0db67cc Merge branch 'obsd-master' 2016-05-27 20:01:11 +01:00
nicm
fcb00a4161 Use getprogname() instead of __progname to make portability easier. 2016-05-27 17:05:42 +00:00
Nicholas Marriott
762fa58ce8 Merge branch 'master' of github.com:tmux/tmux 2016-05-27 18:04:45 +01:00
Nicholas Marriott
cfef0c6658 getprogname() and setproctitle() on Linux. 2016-05-27 18:04:25 +01:00
Nicholas Marriott
f2ec81cf21 Add flag for -pg. 2016-05-27 10:37:06 +01:00
Thomas Adam
20d97eb849 Merge branch 'obsd-master' 2016-05-26 18:01:09 +01:00
nicm
ec7f5305b1 Extend 0x1234 keys form to more bits so that Unicode keys work. 2016-05-26 14:49:48 +00:00
Thomas Adam
95e304d111 Merge branch 'obsd-master' 2016-05-26 14:01:10 +01:00
nicm
cd14ac0486 Just nuke environ instead of trying to unsetenv everything because that
doesn't necessarily work if there is an entry with an empty name.
2016-05-26 12:15:42 +00:00
Thomas Adam
05ec232f3e Merge branch 'obsd-master' 2016-05-24 00:01:09 +01:00
Thomas Adam
266918a580 Merge branch 'obsd-master' 2016-05-23 22:01:10 +01:00
nicm
95a4cc3bce Use a fixed buffer for strftime() because there is no portable way to
tell if the buffer is too small, and an expanding buffer is overkill
anyway.
2016-05-23 20:39:26 +00:00
nicm
e81a92449e Remove unused variable, from Ben Boeckel. 2016-05-23 20:03:14 +00:00
Nicholas Marriott
7411f21c5f Use osdep_event_init() so that LIBEVENT_NOEPOLL and so on are set to turn off
broken event methods. Reported by Suraj N Kurapati.
2016-05-20 07:54:30 +01:00
Nicholas Marriott
2377092a70 Merge branch 'master' of github.com:tmux/tmux 2016-05-13 08:32:46 +01:00
Nicholas Marriott
af25cab11b Fix a typo, issue 406. 2016-05-13 08:31:45 +01:00
Thomas Adam
6cb74f4b7d Merge branch 'obsd-master' 2016-05-12 18:01:10 +01:00
tim
fdd368a294 - Rework load_cfg() error handling a little.
- Add -q to source-file to suppress errors about nonexistent files.

Input and OK nicm@
2016-05-12 16:05:33 +00:00
Thomas Adam
3ec7e3c006 Merge branch 'obsd-master' 2016-05-12 16:01:10 +01:00
nicm
9715c61de0 set-hook needs CANFAIL like the other set commands. 2016-05-12 13:21:56 +00:00
Thomas Adam
e76d44a640 Merge branch 'obsd-master' 2016-05-12 00:01:10 +01:00
nicm
373b13b240 Add on alerts rather than ignoring them if the event has already been
queued, for example bell and activity together. From Marcel Lippmann via
Romain Francoise.
2016-05-11 20:56:58 +00:00
Nicholas Marriott
fe4e9470bb Add --static to PKG_CONFIG rather than replacing it. 2016-05-05 15:18:58 +01:00
Nicholas Marriott
29763d006a Do not mention OpenBSD FAQ. 2016-05-05 13:09:22 +01:00
Thomas Adam
f4648c1ca1 Merge branch 'obsd-master' 2016-05-05 00:01:11 +01:00
nicm
9f045787a5 Fix up a couple of long lines. 2016-05-04 21:29:47 +00:00
Thomas Adam
ce1ec90fcc Merge branch 'obsd-master' 2016-05-03 16:01:10 +01:00
nicm
28e0658fa9 Some tidying of copy mode search functions, based on a diff from Lukasz
Piatkowski (initial changes to help some more to come).
2016-05-03 13:40:50 +00:00
Thomas Adam
96538b489b Merge branch 'obsd-master' 2016-05-01 16:01:11 +01:00
nicm
4a6eca5bd7 Use the same code for half page scrolling as full, from Michal Mazurek. 2016-05-01 13:39:05 +00:00
Thomas Adam
fe4ef307b7 Merge branch 'obsd-master' 2016-05-01 14:01:12 +01:00
nicm
87be2da4e1 Missing format (window_activity_flag) and a missing Ta. 2016-05-01 11:46:12 +00:00
Nicholas Marriott
2b9f8ae485 Update TODO. 2016-04-30 20:04:41 +01:00
nicm
88bd5b15ff tty_client_ready can not be internal to tty.c again. 2016-04-30 18:59:02 +00:00
Thomas Adam
5849c950d0 Merge branch 'obsd-master' 2016-04-30 00:01:10 +01:00
jmc
0c7895076e tweak previous; 2016-04-29 20:57:10 +00:00
Thomas Adam
bc4f725820 Merge branch 'obsd-master' 2016-04-29 20:01:09 +01:00
nicm
975aa3ccd6 Expand client formats (like run-shell), from Stephen M Coakley. 2016-04-29 17:12:12 +00:00
Thomas Adam
55d472a9fe Merge branch 'obsd-master' 2016-04-29 18:01:09 +01:00
nicm
eb8e76d433 Compact a small table into text. 2016-04-29 15:58:52 +00:00
Thomas Adam
ba9f32b464 Merge branch 'obsd-master' 2016-04-29 16:01:12 +01:00
nicm
0509be0740 Add option to include status text in the pane borders. If
pane-border-status is set to "top" or "bottom" (rather than "off"),
every pane has a permanent top or bottom border containing the text from
pane-border-format.

Based on a diff sent long ago by Jonathan Slenders, mostly rewritten and
simplified by me.
2016-04-29 15:00:48 +00:00
nicm
0d84fdd953 Final parts of command hooks, add before- and after- hooks to each command. 2016-04-29 14:05:24 +00:00
nicm
c5443da2d3 The backoff timer is causing no end of trouble with disconnected clients
stopping data in attached ones. So get rid of it and see how we get on
with just a high watermark on each pane.
2016-04-29 13:36:10 +00:00
nicm
5f2bfd9807 Make the grid_cell passed into screen_write_* const. 2016-04-29 13:21:33 +00:00
Thomas Adam
e7de2fe552 Merge branch 'obsd-master' 2016-04-29 14:01:09 +01:00
Nicholas Marriott
65e4c57d3a Only assume width 1 when wcwidth() returns -1 on non-OpenBSD platforms. 2016-04-29 12:47:15 +01:00
Thomas Adam
a9d501e975 Merge branch 'obsd-master' 2016-04-29 12:01:09 +01:00
nicm
97417a1813 Fix keys parsing again to correctly accept Unicode when not prefixed
with Escape.
2016-04-29 10:42:16 +00:00
nicm
7abdfbe20e OpenBSD wcwidth() is sensible and complete so if it returns -1 it means
that a character is not printable, so return to ignoring such
characters.
2016-04-29 09:11:19 +00:00
Thomas Adam
7a02910feb Merge branch 'obsd-master' 2016-04-28 10:01:10 +01:00
nicm
dd8ba0b5a8 memmove() the right size when expanding tree. 2016-04-28 07:20:26 +00:00
nicm
36976ce5e6 After unlock, Update activity time after recalculate_sizes() so that the
session attached flag is correct.
2016-04-28 06:51:56 +00:00
Thomas Adam
bac7a68023 Merge branch 'obsd-master' 2016-04-27 20:01:10 +01:00
nicm
fc70ac4d59 Apply backspace check after working out the actual key, so that M-BSpace
can work.
2016-04-27 16:46:21 +00:00
Nicholas Marriott
fb4585bbe0 Merge branch 'master' of github.com:tmux/tmux 2016-04-27 13:10:55 +01:00
Nicholas Marriott
61f231a496 Add to TODO. 2016-04-27 13:10:34 +01:00
Thomas Adam
55fdaab365 Merge branch 'obsd-master' 2016-04-27 12:01:10 +01:00
nicm
1cedf78284 Add next/previous paragraph, from J Raynor. 2016-04-27 09:39:09 +00:00
nicm
23fdbc9ea6 Loads of platforms appear to have old or broken Unicode character type
information and are missing widths for relatively common Unicode
characters (so mbtowc() works, but wcwidth() fails). So if wcwidth()
returns -1, assume a width of 1 instead of ignoring the character.
2016-04-27 09:36:25 +00:00
Thomas Adam
394589d493 Merge branch 'obsd-master' 2016-04-27 00:01:09 +01:00
nicm
d3546cc85c Simplify next key matching and fix problems with meta and Unicode keys. 2016-04-26 22:19:22 +00:00
Nicholas Marriott
447ead940e No more array.h. 2016-04-26 12:06:35 +01:00
Thomas Adam
7b9c0ced21 Merge branch 'obsd-master' 2016-04-26 12:01:09 +01:00
nicm
fb1c929dc6 Remove last uses of array.h. 2016-04-26 10:18:57 +00:00
Thomas Adam
819ad1a007 Merge branch 'obsd-master' 2016-04-26 10:01:16 +01:00
nicm
d303e55258 Log wcwidth() and mbtowc() failure to make it easier to debug a Unicode
codepoint not appearing.
2016-04-26 07:33:36 +00:00
Thomas Adam
3b833a0c01 Merge branch 'obsd-master' 2016-04-25 20:01:10 +01:00
nicm
6bf2a43e67 Don't overwrite modifiers in the buffer when making UTF-8 strings,
append instead.
2016-04-25 17:05:53 +00:00
Thomas Adam
5391342b08 Start working on 2.3 2016-04-11 01:07:07 +01:00
63 changed files with 3009 additions and 2106 deletions

1
.gitignore vendored
View File

@@ -17,3 +17,4 @@ Makefile
Makefile.in
configure
tmux.1.*
*.dSYM

View File

@@ -22,6 +22,7 @@ Pierre-Yves Ritschard <pyr@openbsd.org> pyr <pyr>
Ray Lai <ray@openbsd.org> ray <ray>
Ryan McBride <mcbride@openbsd.org> mcbride <mcbride>
Sebastian Benoit <benno@openbsd.org> benno <benno>
Sebastien Marie <semarie@openbsd.org> semarie <semarie>
Stefan Sperling <stsp@openbsd.org> stsp <stsp>
Stuart Henderson <sthen@openbsd.org> sthen <sthen>
Ted Unangst <tedu@openbsd.org> tedu <tedu>

27
CHANGES
View File

@@ -1,3 +1,24 @@
CHANGES FROM 2.2 to 2.3 29 September 2016
Incompatible Changes
====================
None.
Normal Changes
==============
* New option 'pane-border-status' to add text in the oane borders.
* Support for hooks on commands: 'after' and 'before' hooks.
* 'source-file' understands '-q' to supress errors for nonexistent files.
* Lots of UTF8 improvements, especially on MacOS.
* 'window-status-separator' understands #[] expansions.
* 'split-window' understands '-f' for performing a full-width split.
* Allow report count to be specified when using 'bind-key -R'.
* 'set -a' for appending to user options (@foo) is now supported.
* '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
Incompatible Changes
@@ -217,8 +238,8 @@ Normal Changes
* A new environment variable TMUX_TMPDIR is now honoured, allowing the
socket directory to be set outside of TMPDIR (/tmp/ if not set).
* If -s not given to swap-pane the current pane is assumed.
* A #{pane_syncronized} format specifier has been added to be a conditional
format if a pane is in a syncronised mode (c.f. syncronize-panes)
* A #{pane_synchronized} format specifier has been added to be a conditional
format if a pane is in a synchronised mode (c.f. synchronize-panes)
* Tmux now runs under Cygwin natively.
* Formats can now be nested within each other and expanded accordingly.
* Added 'automatic-rename-format' option to allow the automatic rename
@@ -1018,7 +1039,7 @@ The list of older changes is below.
* -u flag to scroll-mode and copy-mode to start scrolled one page
up. scroll-mode -u is bound to prefix,page-up (ppage) by default.
* Allow status, mode and message attributes to be changed by three new options:
status-attr, mode-attr, message-attr. A comma-separataed list is accepted
status-attr, mode-attr, message-attr. A comma-separated list is accepted
containing: bright, dim, underscore, blink, reverse, hidden, italics, for
example:

View File

@@ -7,7 +7,7 @@ CLEANFILES = tmux.1.mdoc tmux.1.man
# Distribution tarball options.
EXTRA_DIST = \
CHANGES FAQ README TODO COPYING example_tmux.conf compat/*.[ch] \
array.h compat.h tmux.h osdep-*.c xmalloc.h mdoc2man.awk tmux.1
compat.h tmux.h osdep-*.c xmalloc.h mdoc2man.awk tmux.1
dist-hook:
make clean
grep "^#found_debug=" configure
@@ -26,7 +26,7 @@ if IS_GCC
CFLAGS += -std=gnu99 -O2
if IS_DEBUG
CFLAGS += -g
CFLAGS += -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
CFLAGS += -Wno-long-long -Wall -W -Wformat=2
CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
@@ -37,6 +37,10 @@ if IS_COVERAGE
CFLAGS += -g -O0 --coverage
LDFLAGS += --coverage
endif
if IS_PROFILE
CFLAGS += -g -O0 -pg
LDFLAGS += -pg
endif
CPPFLAGS += -iquote.
endif
@@ -181,7 +185,12 @@ dist_tmux_SOURCES = \
xterm-keys.c
nodist_tmux_SOURCES = osdep-@PLATFORM@.c
# Pile in all the compat/ stuff that is needed.
# Add compat file for utf8proc.
if HAVE_UTF8PROC
nodist_tmux_SOURCES += compat/utf8proc.c
endif
# Add compat for missing or broken functions.
if NO_FORKPTY
nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c
endif
@@ -194,6 +203,12 @@ endif
if NO_DAEMON
nodist_tmux_SOURCES += compat/daemon.c
endif
if NO_GETPROGNAME
nodist_tmux_SOURCES += compat/getprogname.c
endif
if NO_SETPROCTITLE
nodist_tmux_SOURCES += compat/setproctitle.c
endif
if NO_SETENV
nodist_tmux_SOURCES += compat/setenv.c
endif

14
README
View File

@@ -33,19 +33,17 @@ the source tree with:
$ nroff -mdoc tmux.1|less
Some common questions are answered in the FAQ file and a more extensive (but
slightly out of date) guide is available in the OpenBSD FAQ at
http://www.openbsd.org/faq/faq7.html#tmux. A rough todo list is in the TODO
file and an example configuration in example_tmux.conf.
Some common questions are answered in the FAQ file, a rough todo list is in the
TODO file and an example configuration in example_tmux.conf.
A vim(1) syntax file is available at:
https://github.com/keith/tmux.vim
https://raw.githubusercontent.com/keith/tmux.vim/master/syntax/tmux.vim
https://github.com/keith/tmux.vim
https://raw.githubusercontent.com/keith/tmux.vim/master/syntax/tmux.vim
And a bash(1) completion file at:
https://github.com/przepompownia/tmux-bash-completion
https://github.com/imomaliev/tmux-bash-completion
For debugging, running tmux with -v or -vv will generate server and client log
files in the current directory.
@@ -58,6 +56,8 @@ And for Git commit emails:
https://groups.google.com/forum/#!forum/tmux-git
Subscribe by sending an email to <tmux-users+subscribe@googlegroups.com>.
Bug reports, feature suggestions and especially code contributions are most
welcome. Please send by email to:

View File

@@ -115,7 +115,7 @@ From there, merge the result in, fixing up any conflicts which might arise.
% git merge obsd-master
Then ensure things look correct by BULDING the result of that sync:
Then ensure things look correct by BUILDING the result of that sync:
% make clean && ./autogen.sh && ./configure && make
@@ -172,5 +172,5 @@ Release tmux for next version
the Makefile. Commit it, and run 'make' to replace %%VERSION%%. Push
the result out.
8. Bump version in tmu/tmux.git configure.ac and uncomment "found_debug=yes" to
8. Bump version in tmux/tmux.git configure.ac and uncomment "found_debug=yes" to
create a debug build by default.

14
TODO
View File

@@ -7,6 +7,7 @@
* last-pane across sessions
* list-keys should quote output so that bindings can just be used in
config file as-is
* resize-pane -p to match split-window -p
- make command sequences more usable
* don't require space after ;
@@ -44,8 +45,6 @@
* bind commands to mouse in different areas?
* commands executed when clicking on a pattern (URL)
- hooks!
- warts on current naming:
* display-time but message-fg/bg/attr
* list-* vs show-*
@@ -72,10 +71,10 @@
table() cb to give the table name ("vi" or "emacs"). anything in the
table fires the command, anything not in the table is injected as a
key
* searching in copy mode should unwrap lines, so if you seach for "foobar"
* searching in copy mode should unwrap lines, so if you search for "foobar"
then it should be found even if it is now "foo\nbar" (if the WRAP flag
is set on the line)
* {} to go to next/previous blank line in copy mode
* capture-pane option to preserve spaces but not join lines
- layout stuff
* way to tag a layout as a number/name
@@ -121,7 +120,12 @@
or even guarantee that cmdq->c != NULL and provide a better way to
tell when in the config file - then we use cmdq->c if we need a
client w/o a session else cmd_current_client
* optimize pane redraws, 20120318184853.GK10965@yelena.nicm.ath.cx
* we do more work than we should if a single read() contains operations
that cancel each other out: for example, writing twice to the same
cell, or writing and then clearing a line; it would be nice to
optimize these. would it mean processing the entire read() data first
then applying changes? or an initial optimization step? or something
else?
- miscellaneous
* way to keep a job running just read its last line of output for #()

View File

@@ -163,15 +163,15 @@ alerts_queue(struct window *w, int flags)
if (!event_initialized(&w->alerts_timer))
evtimer_set(&w->alerts_timer, alerts_timer, w);
if (!alerts_fired) {
if ((w->flags & flags) != flags) {
w->flags |= flags;
log_debug("@%u alerts flags added %#x", w->id, flags);
}
if (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 && 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;
}
}

120
array.h
View File

@@ -1,120 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2006 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.
*/
#ifndef ARRAY_H
#define ARRAY_H
#define ARRAY_INITIALIZER { NULL, 0, 0 }
#define ARRAY_DECL(n, c) \
struct n { \
c *list; \
u_int num; \
size_t space; \
}
#define ARRAY_ITEM(a, i) ((a)->list[i])
#define ARRAY_ITEMSIZE(a) (sizeof *(a)->list)
#define ARRAY_INITIALSPACE(a) (10 * ARRAY_ITEMSIZE(a))
#define ARRAY_ENSURE(a, n) do { \
if (UINT_MAX - (n) < (a)->num) \
fatalx("number too big"); \
if (SIZE_MAX / ((a)->num + (n)) < ARRAY_ITEMSIZE(a)) \
fatalx("size too big"); \
if ((a)->space == 0) { \
(a)->space = ARRAY_INITIALSPACE(a); \
(a)->list = xrealloc((a)->list, (a)->space); \
} \
while ((a)->space <= ((a)->num + (n)) * ARRAY_ITEMSIZE(a)) { \
(a)->list = xreallocarray((a)->list, 2, (a)->space); \
(a)->space *= 2; \
} \
} while (0)
#define ARRAY_EMPTY(a) (((void *) (a)) == NULL || (a)->num == 0)
#define ARRAY_LENGTH(a) ((a)->num)
#define ARRAY_DATA(a) ((a)->list)
#define ARRAY_FIRST(a) ARRAY_ITEM(a, 0)
#define ARRAY_LAST(a) ARRAY_ITEM(a, (a)->num - 1)
#define ARRAY_INIT(a) do { \
(a)->num = 0; \
(a)->list = NULL; \
(a)->space = 0; \
} while (0)
#define ARRAY_CLEAR(a) do { \
(a)->num = 0; \
} while (0)
#define ARRAY_SET(a, i, s) do { \
(a)->list[i] = s; \
} while (0)
#define ARRAY_ADD(a, s) do { \
ARRAY_ENSURE(a, 1); \
(a)->list[(a)->num] = s; \
(a)->num++; \
} while (0)
#define ARRAY_INSERT(a, i, s) do { \
ARRAY_ENSURE(a, 1); \
if ((i) < (a)->num) { \
memmove((a)->list + (i) + 1, (a)->list + (i), \
ARRAY_ITEMSIZE(a) * ((a)->num - (i))); \
} \
(a)->list[i] = s; \
(a)->num++; \
} while (0)
#define ARRAY_REMOVE(a, i) do { \
if ((i) < (a)->num - 1) { \
memmove((a)->list + (i), (a)->list + (i) + 1, \
ARRAY_ITEMSIZE(a) * ((a)->num - (i) - 1)); \
} \
(a)->num--; \
if ((a)->num == 0) \
ARRAY_FREE(a); \
} while (0)
#define ARRAY_EXPAND(a, n) do { \
ARRAY_ENSURE(a, n); \
(a)->num += n; \
} while (0)
#define ARRAY_TRUNC(a, n) do { \
if ((a)->num > n) \
(a)->num -= n; \
else \
ARRAY_FREE(a); \
} while (0)
#define ARRAY_CONCAT(a, b) do { \
ARRAY_ENSURE(a, (b)->num); \
memcpy((a)->list + (a)->num, (b)->list, (b)->num * ARRAY_ITEMSIZE(a)); \
(a)->num += (b)->num; \
} while (0)
#define ARRAY_FREE(a) do { \
free((a)->list); \
ARRAY_INIT(a); \
} while (0)
#define ARRAY_FREEALL(a) do { \
ARRAY_FREE(a); \
free(a); \
} while (0)
#endif

24
cfg.c
View File

@@ -47,8 +47,8 @@ set_cfg_file(const char *path)
void
start_cfg(void)
{
char *cause = NULL;
const char *home;
int quiet = 0;
cfg_cmd_q = cmdq_new(NULL);
cfg_cmd_q->emptyfn = cfg_default_done;
@@ -60,28 +60,20 @@ start_cfg(void)
if (cfg_client != NULL)
cfg_client->references++;
if (access(TMUX_CONF, R_OK) == 0) {
if (load_cfg(TMUX_CONF, cfg_cmd_q, &cause) == -1)
cfg_add_cause("%s: %s", TMUX_CONF, cause);
} else if (errno != ENOENT)
cfg_add_cause("%s: %s", TMUX_CONF, strerror(errno));
load_cfg(TMUX_CONF, cfg_cmd_q, 1);
if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmux.conf", home);
if (access(cfg_file, R_OK) != 0 && errno == ENOENT) {
free(cfg_file);
cfg_file = NULL;
}
quiet = 1;
}
if (cfg_file != NULL && load_cfg(cfg_file, cfg_cmd_q, &cause) == -1)
cfg_add_cause("%s: %s", cfg_file, cause);
free(cause);
if (cfg_file != NULL)
load_cfg(cfg_file, cfg_cmd_q, quiet);
cmdq_continue(cfg_cmd_q);
}
int
load_cfg(const char *path, struct cmd_q *cmdq, char **cause)
load_cfg(const char *path, struct cmd_q *cmdq, int quiet)
{
FILE *f;
char delim[3] = { '\\', '\\', '\0' };
@@ -92,7 +84,9 @@ load_cfg(const char *path, struct cmd_q *cmdq, char **cause)
log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) {
xasprintf(cause, "%s: %s", path, strerror(errno));
if (errno == ENOENT && quiet)
return (0);
cfg_add_cause("%s: %s", path, strerror(errno));
return (-1);
}

View File

@@ -36,9 +36,9 @@ const struct cmd_entry cmd_bind_key_entry = {
.name = "bind-key",
.alias = "bind",
.args = { "cnrt:T:", 1, -1 },
.usage = "[-cnr] [-t mode-table] [-T key-table] key command "
"[arguments]",
.args = { "cnrR:t:T:", 1, -1 },
.usage = "[-cnr] [-t mode-table] [-R repeat-count] [-T key-table] key "
"command [arguments]",
.flags = 0,
.exec = cmd_bind_key_exec
@@ -97,11 +97,12 @@ enum cmd_retval
cmd_bind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, key_code key)
{
struct args *args = self->args;
const char *tablename;
const char *tablename, *arg;
const struct mode_key_table *mtab;
struct mode_key_binding *mbind, mtmp;
enum mode_key_cmd cmd;
const char *arg;
char *cause;
u_int repeat;
tablename = args_get(args, 't');
if ((mtab = mode_key_findtable(tablename)) == NULL) {
@@ -145,6 +146,16 @@ cmd_bind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, key_code key)
break;
}
repeat = 1;
if (args_has(args, 'R')) {
repeat = args_strtonum(args, 'R', 1, SHRT_MAX, &cause);
if (cause != NULL) {
cmdq_error(cmdq, "repeat count %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
mtmp.key = key;
mtmp.mode = !!args_has(args, 'c');
if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) == NULL) {
@@ -153,6 +164,7 @@ cmd_bind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, key_code key)
mbind->mode = mtmp.mode;
RB_INSERT(mode_key_tree, mtab->tree, mbind);
}
mbind->repeat = repeat;
mbind->cmd = cmd;
mbind->arg = arg != NULL ? xstrdup(arg) : NULL;
return (CMD_RETURN_NORMAL);

View File

@@ -83,7 +83,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq)
window_copy_start_drag(c, &cmdq->item->mouse);
}
if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
window_copy_pageup(wp);
window_copy_pageup(wp, 0);
return (CMD_RETURN_NORMAL);
}

View File

@@ -78,9 +78,10 @@ cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq)
msg = format_expand_time(ft, template, time(NULL));
if (args_has(self->args, 'p'))
cmdq_print(cmdq, "%s", msg);
else
else if (c != NULL)
status_message_set(c, "%s", msg);
free(msg);
format_free(ft);
return (CMD_RETURN_NORMAL);

View File

@@ -18,19 +18,25 @@
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Display panes on a client.
*/
enum cmd_retval cmd_display_panes_exec(struct cmd *, struct cmd_q *);
static enum cmd_retval cmd_display_panes_exec(struct cmd *, struct cmd_q *);
static void cmd_display_panes_callback(struct client *,
struct window_pane *);
const struct cmd_entry cmd_display_panes_entry = {
.name = "display-panes",
.alias = "displayp",
.args = { "t:", 0, 0 },
.args = { "t:", 0, 1 },
.usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
@@ -39,10 +45,53 @@ const struct cmd_entry cmd_display_panes_entry = {
.exec = cmd_display_panes_exec
};
enum cmd_retval
cmd_display_panes_exec(__unused struct cmd *self, struct cmd_q *cmdq)
static enum cmd_retval
cmd_display_panes_exec(struct cmd *self, struct cmd_q *cmdq)
{
server_set_identify(cmdq->state.c);
struct args *args = self->args;
struct client *c = cmdq->state.c;
if (c->identify_callback != NULL)
return (CMD_RETURN_NORMAL);
c->identify_callback = cmd_display_panes_callback;
if (args->argc != 0)
c->identify_callback_data = xstrdup(args->argv[0]);
else
c->identify_callback_data = xstrdup("select-pane -t '%%'");
server_set_identify(c);
return (CMD_RETURN_NORMAL);
}
static void
cmd_display_panes_callback(struct client *c, struct window_pane *wp)
{
struct cmd_list *cmdlist;
char *template, *cmd, *expanded, *cause;
template = c->identify_callback_data;
if (wp != NULL) {
xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(template, expanded, 1);
if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(c, "%s", cause);
free(cause);
}
} else {
cmdq_run(c->cmdq, cmdlist, NULL);
cmd_list_free(cmdlist);
}
free(cmd);
free(expanded);
}
free(c->identify_callback_data);
c->identify_callback_data = NULL;
c->identify_callback = NULL;
}

View File

@@ -81,7 +81,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
cwd = NULL;
ft = format_create(cmdq, 0);
format_defaults(ft, NULL, s, wl, wp);
format_defaults(ft, cmdq->state.c, s, wl, wp);
shellcmd = format_expand(ft, args->argv[0]);
format_free(ft);
@@ -157,6 +157,7 @@ cmd_if_shell_callback(struct job *job)
}
cmdq1 = cmdq_new(cmdq->client);
cmdq1->flags |= cmdq->flags & CMD_Q_NOHOOKS;
cmdq1->emptyfn = cmd_if_shell_done;
cmdq1->data = cdata;

View File

@@ -124,7 +124,7 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
else
size = (dst_wp->sx * percentage) / 100;
}
lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'));
lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'), 0);
if (lc == NULL) {
cmdq_error(cmdq, "create pane failed: pane too small");
return (CMD_RETURN_ERROR);
@@ -135,11 +135,6 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
window_lost_pane(src_w, src_wp);
TAILQ_REMOVE(&src_w->panes, src_wp, entry);
if (window_count_panes(src_w) == 0)
server_kill_window(src_w);
else
notify_window_layout_changed(src_w);
src_wp->window = dst_w;
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp);
@@ -156,6 +151,11 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
} else
server_status_session(dst_s);
if (window_count_panes(src_w) == 0)
server_kill_window(src_w);
else
notify_window_layout_changed(src_w);
notify_window_layout_changed(dst_w);
return (CMD_RETURN_NORMAL);
}

View File

@@ -27,10 +27,10 @@
* List key bindings.
*/
enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmd_q *);
static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmd_q *);
enum cmd_retval cmd_list_keys_table(struct cmd *, struct cmd_q *);
enum cmd_retval cmd_list_keys_commands(struct cmd_q *);
static enum cmd_retval cmd_list_keys_table(struct cmd *, struct cmd_q *);
static enum cmd_retval cmd_list_keys_commands(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_list_keys_entry = {
.name = "list-keys",
@@ -47,14 +47,14 @@ const struct cmd_entry cmd_list_commands_entry = {
.name = "list-commands",
.alias = "lscm",
.args = { "", 0, 0 },
.usage = "",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.flags = CMD_STARTSERVER,
.exec = cmd_list_keys_exec
};
enum cmd_retval
static enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
@@ -65,7 +65,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
int repeat, width, tablewidth, keywidth;
if (self->entry == &cmd_list_commands_entry)
return (cmd_list_keys_commands(cmdq));
return (cmd_list_keys_commands(self, cmdq));
if (args_has(args, 't'))
return (cmd_list_keys_table(self, cmdq));
@@ -131,15 +131,15 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL);
}
enum cmd_retval
static enum cmd_retval
cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
const char *tablename;
const char *tablename, *key, *cmdstr, *mode;
const struct mode_key_table *mtab;
struct mode_key_binding *mbind;
const char *key, *cmdstr, *mode;
int width, keywidth, any_mode;
char repeat[16];
int width, keywidth, repeatwidth, any_mode;
tablename = args_get(args, 't');
if ((mtab = mode_key_findtable(tablename)) == NULL) {
@@ -147,7 +147,7 @@ cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR);
}
width = 0;
keywidth = repeatwidth = 0;
any_mode = 0;
RB_FOREACH(mbind, mode_key_tree, mtab->tree) {
key = key_string_lookup_key(mbind->key);
@@ -155,9 +155,16 @@ cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq)
if (mbind->mode != 0)
any_mode = 1;
keywidth = strlen(key);
if (keywidth > width)
width = keywidth;
width = strlen(key);
if (width > keywidth)
keywidth = width;
if (mbind->repeat != 1) {
snprintf(repeat, sizeof repeat, "%u", mbind->repeat);
width = strlen(repeat);
if (width > repeatwidth)
repeatwidth = width;
}
}
RB_FOREACH(mbind, mode_key_tree, mtab->tree) {
@@ -166,11 +173,17 @@ cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq)
mode = "";
if (mbind->mode != 0)
mode = "c";
snprintf(repeat, sizeof repeat, "%u", mbind->repeat);
cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd);
if (cmdstr != NULL) {
cmdq_print(cmdq, "bind-key -%st %s%s %*s %s%s%s%s",
cmdq_print(cmdq,
"bind-key -%st %s%s%s%*s %*s %s%s%s%s",
mode, any_mode && *mode == '\0' ? " " : "",
mtab->name, (int) width, key, cmdstr,
mtab->name,
mbind->repeat != 1 ? " -R " :
(repeatwidth == 0 ? "" : " "),
repeatwidth, mbind->repeat != 1 ? repeat : "",
(int)keywidth, key, cmdstr,
mbind->arg != NULL ? " \"" : "",
mbind->arg != NULL ? mbind->arg : "",
mbind->arg != NULL ? "\"": "");
@@ -180,21 +193,44 @@ cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL);
}
enum cmd_retval
cmd_list_keys_commands(struct cmd_q *cmdq)
static enum cmd_retval
cmd_list_keys_commands(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
const struct cmd_entry **entryp;
const struct cmd_entry *entry;
struct format_tree *ft;
const char *template;
char *line;
if ((template = args_get(args, 'F')) == NULL) {
template = "#{command_list_name}"
"#{?command_list_alias, (#{command_list_alias}),} "
"#{command_list_usage}";
}
ft = format_create(cmdq, 0);
format_defaults(ft, NULL, NULL, NULL, NULL);
for (entryp = cmd_table; *entryp != NULL; entryp++) {
entry = *entryp;
if (entry->alias == NULL) {
cmdq_print(cmdq, "%s %s", entry->name, entry->usage);
continue;
format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL) {
format_add(ft, "command_list_alias", "%s",
entry->alias);
}
cmdq_print(cmdq, "%s (%s) %s", entry->name, entry->alias,
entry->usage);
if (entry->alias != NULL) {
format_add(ft, "command_list_usage", "%s",
entry->usage);
}
line = format_expand(ft, template);
if (*line != '\0')
cmdq_print(cmdq, "%s", line);
free(line);
}
format_free(ft);
return (CMD_RETURN_NORMAL);
}

View File

@@ -80,7 +80,7 @@ cmdq_print(struct cmd_q *cmdq, const char *fmt, ...)
/* nothing */;
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
if (~c->flags & CLIENT_UTF8) {
vasprintf(&tmp, fmt, ap);
xvasprintf(&tmp, fmt, ap);
msg = utf8_sanitize(tmp);
free(tmp);
evbuffer_add(c->stdout_data, msg, strlen(msg));
@@ -186,6 +186,9 @@ static enum cmd_retval
cmdq_continue_one(struct cmd_q *cmdq)
{
struct cmd *cmd = cmdq->cmd;
const char *name = cmd->entry->name;
struct session *s;
struct hooks *hooks;
enum cmd_retval retval;
char *tmp;
int flags = !!(cmd->flags & CMD_CONTROL);
@@ -197,19 +200,51 @@ cmdq_continue_one(struct cmd_q *cmdq)
cmdq->time = time(NULL);
cmdq->number++;
cmdq_guard(cmdq, "begin", flags);
if (~cmdq->flags & CMD_Q_REENTRY)
cmdq_guard(cmdq, "begin", flags);
if (cmd_prepare_state(cmd, cmdq, NULL) != 0)
if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)
goto error;
if (~cmdq->flags & CMD_Q_NOHOOKS) {
s = NULL;
if (cmdq->state.tflag.s != NULL)
s = cmdq->state.tflag.s;
else if (cmdq->state.sflag.s != NULL)
s = cmdq->state.sflag.s;
else if (cmdq->state.c != NULL)
s = cmdq->state.c->session;
if (s != NULL)
hooks = s->hooks;
else
hooks = global_hooks;
if (~cmdq->flags & CMD_Q_REENTRY) {
cmdq->flags |= CMD_Q_REENTRY;
if (hooks_wait(hooks, cmdq, NULL,
"before-%s", name) == 0)
return (CMD_RETURN_WAIT);
if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)
goto error;
}
} else
hooks = NULL;
cmdq->flags &= ~CMD_Q_REENTRY;
retval = cmd->entry->exec(cmd, cmdq);
if (retval == CMD_RETURN_ERROR)
goto error;
if (hooks != NULL && hooks_wait(hooks, cmdq, NULL,
"after-%s", name) == 0)
retval = CMD_RETURN_WAIT;
cmdq_guard(cmdq, "end", flags);
return (retval);
error:
cmdq_guard(cmdq, "error", flags);
cmdq->flags &= ~CMD_Q_REENTRY;
return (CMD_RETURN_ERROR);
}
@@ -232,11 +267,18 @@ cmdq_continue(struct cmd_q *cmdq)
if (empty)
goto empty;
if (cmdq->item == NULL) {
cmdq->item = TAILQ_FIRST(&cmdq->queue);
cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
} else
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
/*
* If the command isn't in the middle of running hooks (due to
* CMD_RETURN_WAIT), move onto the next command; otherwise, leave the
* state of the queue as it is.
*/
if (~cmdq->flags & CMD_Q_REENTRY) {
if (cmdq->item == NULL) {
cmdq->item = TAILQ_FIRST(&cmdq->queue);
cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
} else
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
}
do {
while (cmdq->cmd != NULL) {

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_set_hook_entry = {
.args = { "gt:u", 1, 2 },
.usage = "[-gu] " CMD_TARGET_SESSION_USAGE " hook-name [command]",
.tflag = CMD_SESSION,
.tflag = CMD_SESSION_CANFAIL,
.flags = 0,
.exec = cmd_set_hook_exec
@@ -63,12 +63,21 @@ cmd_set_hook_exec(struct cmd *self, struct cmd_q *cmdq)
struct hooks *hooks;
struct hook *hook;
char *cause, *tmp;
const char *name, *cmd;
const char *name, *cmd, *target;
if (args_has(args, 'g'))
hooks = global_hooks;
else
else {
if (cmdq->state.tflag.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(cmdq, "no such session: %s", target);
else
cmdq_error(cmdq, "no current session");
return (CMD_RETURN_ERROR);
}
hooks = cmdq->state.tflag.s->hooks;
}
if (self->entry == &cmd_show_hooks_entry) {
hook = hooks_first(hooks);

View File

@@ -200,6 +200,17 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq)
status_timer_start_all();
if (strcmp(oe->name, "monitor-silence") == 0)
alerts_reset_all();
if (strcmp(oe->name, "window-style") == 0 ||
strcmp(oe->name, "window-active-style") == 0) {
RB_FOREACH(w, windows, &windows)
w->flags |= WINDOW_STYLECHANGED;
}
/* When the pane-border-status option has been changed, resize panes. */
if (strcmp(oe->name, "pane-border-status") == 0) {
RB_FOREACH(w, windows, &windows)
layout_fix_panes(w, w->sx, w->sy);
}
/* Update sizes and redraw. May not need it but meh. */
recalculate_sizes();
@@ -216,10 +227,11 @@ enum cmd_retval
cmd_set_option_user(struct cmd *self, struct cmd_q *cmdq, const char *optstr,
const char *valstr)
{
struct args *args = self->args;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
struct options *oo;
struct args *args = self->args;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
struct options *oo;
struct options_entry *o;
if (args_has(args, 's'))
oo = global_options;
@@ -251,18 +263,22 @@ cmd_set_option_user(struct cmd *self, struct cmd_q *cmdq, const char *optstr,
}
options_remove(oo, optstr);
} else {
if (valstr == NULL) {
cmdq_error(cmdq, "empty value");
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'o') && options_find1(oo, optstr) != NULL) {
o = options_find1(oo, optstr);
if (args_has(args, 'o') && o != NULL) {
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "already set: %s", optstr);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
options_set_string(oo, optstr, "%s", valstr);
if (valstr == NULL) {
cmdq_error(cmdq, "empty value");
return (CMD_RETURN_ERROR);
}
if (o != NULL && args_has(args, 'a'))
options_set_string(oo, optstr, "%s%s", o->str, valstr);
else
options_set_string(oo, optstr, "%s", valstr);
}
return (CMD_RETURN_NORMAL);
}

View File

@@ -34,8 +34,8 @@ const struct cmd_entry cmd_source_file_entry = {
.name = "source-file",
.alias = "source",
.args = { "", 1, 1 },
.usage = "path",
.args = { "q", 1, 1 },
.usage = "[-q] path",
.flags = 0,
.exec = cmd_source_file_exec
@@ -46,27 +46,26 @@ cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct cmd_q *cmdq1;
char *cause;
int quiet;
cmdq1 = cmdq_new(cmdq->client);
cmdq1->flags |= cmdq->flags & CMD_Q_NOHOOKS;
cmdq1->emptyfn = cmd_source_file_done;
cmdq1->data = cmdq;
switch (load_cfg(args->argv[0], cmdq1, &cause)) {
quiet = args_has(args, 'q');
switch (load_cfg(args->argv[0], cmdq1, quiet)) {
case -1:
cmdq_free(cmdq1);
if (cfg_references == 0) {
cmdq_free(cmdq1);
cmdq_error(cmdq, "%s", cause);
free(cause);
cfg_print_causes(cmdq);
return (CMD_RETURN_ERROR);
}
cfg_add_cause("%s", cause);
free(cause);
/* FALLTHROUGH */
return (CMD_RETURN_NORMAL);
case 0:
cmdq_free(cmdq1);
if (cfg_references == 0)
cfg_print_causes(cmdq);
cmdq_free(cmdq1);
return (CMD_RETURN_NORMAL);
}

View File

@@ -38,8 +38,8 @@ const struct cmd_entry cmd_split_window_entry = {
.name = "split-window",
.alias = "splitw",
.args = { "bc:dF:l:hp:Pt:v", 0, -1 },
.usage = "[-bdhvP] [-c start-directory] [-F format] "
.args = { "bc:dfF:l:hp:Pt:v", 0, -1 },
.usage = "[-bdfhvP] [-c start-directory] [-F format] "
"[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]",
.tflag = CMD_PANE,
@@ -130,12 +130,13 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
if (*shell == '\0' || areshell(shell))
shell = _PATH_BSHELL;
lc = layout_split_pane(wp, type, size, args_has(args, 'b'));
lc = layout_split_pane(wp, type, size, args_has(args, 'b'),
args_has(args, 'f'));
if (lc == NULL) {
cause = xstrdup("pane too small");
goto error;
}
new_wp = window_add_pane(w, hlimit);
new_wp = window_add_pane(w, wp, hlimit);
layout_assign_pane(lc, new_wp);
path = NULL;

389
colour.c
View File

@@ -2,6 +2,7 @@
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2016 Avi Halachmi <avihpit@yahoo.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -24,334 +25,83 @@
#include "tmux.h"
/*
* Colour to string conversion functions. Bit 8 of the colour means it is one
* of the 256 colour palette.
*/
struct colour_rgb {
u_char i;
u_char r;
u_char g;
u_char b;
};
const struct colour_rgb colour_from_256[] = {
{ 0, 0x00, 0x00, 0x00 }, { 1, 0x00, 0x00, 0x5f },
{ 2, 0x00, 0x00, 0x87 }, { 3, 0x00, 0x00, 0xaf },
{ 4, 0x00, 0x00, 0xd7 }, { 5, 0x00, 0x00, 0xff },
{ 6, 0x00, 0x5f, 0x00 }, { 7, 0x00, 0x5f, 0x5f },
{ 8, 0x00, 0x5f, 0x87 }, { 9, 0x00, 0x5f, 0xaf },
{ 10, 0x00, 0x5f, 0xd7 }, { 11, 0x00, 0x5f, 0xff },
{ 12, 0x00, 0x87, 0x00 }, { 13, 0x00, 0x87, 0x5f },
{ 14, 0x00, 0x87, 0x87 }, { 15, 0x00, 0x87, 0xaf },
{ 16, 0x00, 0x87, 0xd7 }, { 17, 0x00, 0x87, 0xff },
{ 18, 0x00, 0xaf, 0x00 }, { 19, 0x00, 0xaf, 0x5f },
{ 20, 0x00, 0xaf, 0x87 }, { 21, 0x00, 0xaf, 0xaf },
{ 22, 0x00, 0xaf, 0xd7 }, { 23, 0x00, 0xaf, 0xff },
{ 24, 0x00, 0xd7, 0x00 }, { 25, 0x00, 0xd7, 0x5f },
{ 26, 0x00, 0xd7, 0x87 }, { 27, 0x00, 0xd7, 0xaf },
{ 28, 0x00, 0xd7, 0xd7 }, { 29, 0x00, 0xd7, 0xff },
{ 30, 0x00, 0xff, 0x00 }, { 31, 0x00, 0xff, 0x5f },
{ 32, 0x00, 0xff, 0x87 }, { 33, 0x00, 0xff, 0xaf },
{ 34, 0x00, 0xff, 0xd7 }, { 35, 0x00, 0xff, 0xff },
{ 36, 0x5f, 0x00, 0x00 }, { 37, 0x5f, 0x00, 0x5f },
{ 38, 0x5f, 0x00, 0x87 }, { 39, 0x5f, 0x00, 0xaf },
{ 40, 0x5f, 0x00, 0xd7 }, { 41, 0x5f, 0x00, 0xff },
{ 42, 0x5f, 0x5f, 0x00 }, { 43, 0x5f, 0x5f, 0x5f },
{ 44, 0x5f, 0x5f, 0x87 }, { 45, 0x5f, 0x5f, 0xaf },
{ 46, 0x5f, 0x5f, 0xd7 }, { 47, 0x5f, 0x5f, 0xff },
{ 48, 0x5f, 0x87, 0x00 }, { 49, 0x5f, 0x87, 0x5f },
{ 50, 0x5f, 0x87, 0x87 }, { 51, 0x5f, 0x87, 0xaf },
{ 52, 0x5f, 0x87, 0xd7 }, { 53, 0x5f, 0x87, 0xff },
{ 54, 0x5f, 0xaf, 0x00 }, { 55, 0x5f, 0xaf, 0x5f },
{ 56, 0x5f, 0xaf, 0x87 }, { 57, 0x5f, 0xaf, 0xaf },
{ 58, 0x5f, 0xaf, 0xd7 }, { 59, 0x5f, 0xaf, 0xff },
{ 60, 0x5f, 0xd7, 0x00 }, { 61, 0x5f, 0xd7, 0x5f },
{ 62, 0x5f, 0xd7, 0x87 }, { 63, 0x5f, 0xd7, 0xaf },
{ 64, 0x5f, 0xd7, 0xd7 }, { 65, 0x5f, 0xd7, 0xff },
{ 66, 0x5f, 0xff, 0x00 }, { 67, 0x5f, 0xff, 0x5f },
{ 68, 0x5f, 0xff, 0x87 }, { 69, 0x5f, 0xff, 0xaf },
{ 70, 0x5f, 0xff, 0xd7 }, { 71, 0x5f, 0xff, 0xff },
{ 72, 0x87, 0x00, 0x00 }, { 73, 0x87, 0x00, 0x5f },
{ 74, 0x87, 0x00, 0x87 }, { 75, 0x87, 0x00, 0xaf },
{ 76, 0x87, 0x00, 0xd7 }, { 77, 0x87, 0x00, 0xff },
{ 78, 0x87, 0x5f, 0x00 }, { 79, 0x87, 0x5f, 0x5f },
{ 80, 0x87, 0x5f, 0x87 }, { 81, 0x87, 0x5f, 0xaf },
{ 82, 0x87, 0x5f, 0xd7 }, { 83, 0x87, 0x5f, 0xff },
{ 84, 0x87, 0x87, 0x00 }, { 85, 0x87, 0x87, 0x5f },
{ 86, 0x87, 0x87, 0x87 }, { 87, 0x87, 0x87, 0xaf },
{ 88, 0x87, 0x87, 0xd7 }, { 89, 0x87, 0x87, 0xff },
{ 90, 0x87, 0xaf, 0x00 }, { 91, 0x87, 0xaf, 0x5f },
{ 92, 0x87, 0xaf, 0x87 }, { 93, 0x87, 0xaf, 0xaf },
{ 94, 0x87, 0xaf, 0xd7 }, { 95, 0x87, 0xaf, 0xff },
{ 96, 0x87, 0xd7, 0x00 }, { 97, 0x87, 0xd7, 0x5f },
{ 98, 0x87, 0xd7, 0x87 }, { 99, 0x87, 0xd7, 0xaf },
{ 100, 0x87, 0xd7, 0xd7 }, { 101, 0x87, 0xd7, 0xff },
{ 102, 0x87, 0xff, 0x00 }, { 103, 0x87, 0xff, 0x5f },
{ 104, 0x87, 0xff, 0x87 }, { 105, 0x87, 0xff, 0xaf },
{ 106, 0x87, 0xff, 0xd7 }, { 107, 0x87, 0xff, 0xff },
{ 108, 0xaf, 0x00, 0x00 }, { 109, 0xaf, 0x00, 0x5f },
{ 110, 0xaf, 0x00, 0x87 }, { 111, 0xaf, 0x00, 0xaf },
{ 112, 0xaf, 0x00, 0xd7 }, { 113, 0xaf, 0x00, 0xff },
{ 114, 0xaf, 0x5f, 0x00 }, { 115, 0xaf, 0x5f, 0x5f },
{ 116, 0xaf, 0x5f, 0x87 }, { 117, 0xaf, 0x5f, 0xaf },
{ 118, 0xaf, 0x5f, 0xd7 }, { 119, 0xaf, 0x5f, 0xff },
{ 120, 0xaf, 0x87, 0x00 }, { 121, 0xaf, 0x87, 0x5f },
{ 122, 0xaf, 0x87, 0x87 }, { 123, 0xaf, 0x87, 0xaf },
{ 124, 0xaf, 0x87, 0xd7 }, { 125, 0xaf, 0x87, 0xff },
{ 126, 0xaf, 0xaf, 0x00 }, { 127, 0xaf, 0xaf, 0x5f },
{ 128, 0xaf, 0xaf, 0x87 }, { 129, 0xaf, 0xaf, 0xaf },
{ 130, 0xaf, 0xaf, 0xd7 }, { 131, 0xaf, 0xaf, 0xff },
{ 132, 0xaf, 0xd7, 0x00 }, { 133, 0xaf, 0xd7, 0x5f },
{ 134, 0xaf, 0xd7, 0x87 }, { 135, 0xaf, 0xd7, 0xaf },
{ 136, 0xaf, 0xd7, 0xd7 }, { 137, 0xaf, 0xd7, 0xff },
{ 138, 0xaf, 0xff, 0x00 }, { 139, 0xaf, 0xff, 0x5f },
{ 140, 0xaf, 0xff, 0x87 }, { 141, 0xaf, 0xff, 0xaf },
{ 142, 0xaf, 0xff, 0xd7 }, { 143, 0xaf, 0xff, 0xff },
{ 144, 0xd7, 0x00, 0x00 }, { 145, 0xd7, 0x00, 0x5f },
{ 146, 0xd7, 0x00, 0x87 }, { 147, 0xd7, 0x00, 0xaf },
{ 148, 0xd7, 0x00, 0xd7 }, { 149, 0xd7, 0x00, 0xff },
{ 150, 0xd7, 0x5f, 0x00 }, { 151, 0xd7, 0x5f, 0x5f },
{ 152, 0xd7, 0x5f, 0x87 }, { 153, 0xd7, 0x5f, 0xaf },
{ 154, 0xd7, 0x5f, 0xd7 }, { 155, 0xd7, 0x5f, 0xff },
{ 156, 0xd7, 0x87, 0x00 }, { 157, 0xd7, 0x87, 0x5f },
{ 158, 0xd7, 0x87, 0x87 }, { 159, 0xd7, 0x87, 0xaf },
{ 160, 0xd7, 0x87, 0xd7 }, { 161, 0xd7, 0x87, 0xff },
{ 162, 0xd7, 0xaf, 0x00 }, { 163, 0xd7, 0xaf, 0x5f },
{ 164, 0xd7, 0xaf, 0x87 }, { 165, 0xd7, 0xaf, 0xaf },
{ 166, 0xd7, 0xaf, 0xd7 }, { 167, 0xd7, 0xaf, 0xff },
{ 168, 0xd7, 0xd7, 0x00 }, { 169, 0xd7, 0xd7, 0x5f },
{ 170, 0xd7, 0xd7, 0x87 }, { 171, 0xd7, 0xd7, 0xaf },
{ 172, 0xd7, 0xd7, 0xd7 }, { 173, 0xd7, 0xd7, 0xff },
{ 174, 0xd7, 0xff, 0x00 }, { 175, 0xd7, 0xff, 0x5f },
{ 176, 0xd7, 0xff, 0x87 }, { 177, 0xd7, 0xff, 0xaf },
{ 178, 0xd7, 0xff, 0xd7 }, { 179, 0xd7, 0xff, 0xff },
{ 180, 0xff, 0x00, 0x00 }, { 181, 0xff, 0x00, 0x5f },
{ 182, 0xff, 0x00, 0x87 }, { 183, 0xff, 0x00, 0xaf },
{ 184, 0xff, 0x00, 0xd7 }, { 185, 0xff, 0x00, 0xff },
{ 186, 0xff, 0x5f, 0x00 }, { 187, 0xff, 0x5f, 0x5f },
{ 188, 0xff, 0x5f, 0x87 }, { 189, 0xff, 0x5f, 0xaf },
{ 190, 0xff, 0x5f, 0xd7 }, { 191, 0xff, 0x5f, 0xff },
{ 192, 0xff, 0x87, 0x00 }, { 193, 0xff, 0x87, 0x5f },
{ 194, 0xff, 0x87, 0x87 }, { 195, 0xff, 0x87, 0xaf },
{ 196, 0xff, 0x87, 0xd7 }, { 197, 0xff, 0x87, 0xff },
{ 198, 0xff, 0xaf, 0x00 }, { 199, 0xff, 0xaf, 0x5f },
{ 200, 0xff, 0xaf, 0x87 }, { 201, 0xff, 0xaf, 0xaf },
{ 202, 0xff, 0xaf, 0xd7 }, { 203, 0xff, 0xaf, 0xff },
{ 204, 0xff, 0xd7, 0x00 }, { 205, 0xff, 0xd7, 0x5f },
{ 206, 0xff, 0xd7, 0x87 }, { 207, 0xff, 0xd7, 0xaf },
{ 208, 0xff, 0xd7, 0xd7 }, { 209, 0xff, 0xd7, 0xff },
{ 210, 0xff, 0xff, 0x00 }, { 211, 0xff, 0xff, 0x5f },
{ 212, 0xff, 0xff, 0x87 }, { 213, 0xff, 0xff, 0xaf },
{ 214, 0xff, 0xff, 0xd7 }, { 215, 0xff, 0xff, 0xff },
{ 216, 0x08, 0x08, 0x08 }, { 217, 0x12, 0x12, 0x12 },
{ 218, 0x1c, 0x1c, 0x1c }, { 219, 0x26, 0x26, 0x26 },
{ 220, 0x30, 0x30, 0x30 }, { 221, 0x3a, 0x3a, 0x3a },
{ 222, 0x44, 0x44, 0x44 }, { 223, 0x4e, 0x4e, 0x4e },
{ 224, 0x58, 0x58, 0x58 }, { 225, 0x62, 0x62, 0x62 },
{ 226, 0x6c, 0x6c, 0x6c }, { 227, 0x76, 0x76, 0x76 },
{ 228, 0x80, 0x80, 0x80 }, { 229, 0x8a, 0x8a, 0x8a },
{ 230, 0x94, 0x94, 0x94 }, { 231, 0x9e, 0x9e, 0x9e },
{ 232, 0xa8, 0xa8, 0xa8 }, { 233, 0xb2, 0xb2, 0xb2 },
{ 234, 0xbc, 0xbc, 0xbc }, { 235, 0xc6, 0xc6, 0xc6 },
{ 236, 0xd0, 0xd0, 0xd0 }, { 237, 0xda, 0xda, 0xda },
{ 238, 0xe4, 0xe4, 0xe4 }, { 239, 0xee, 0xee, 0xee },
};
const struct colour_rgb colour_to_256[] = {
{ 0, 0x00, 0x00, 0x00 }, { 1, 0x00, 0x00, 0x5f },
{ 2, 0x00, 0x00, 0x87 }, { 3, 0x00, 0x00, 0xaf },
{ 4, 0x00, 0x00, 0xd7 }, { 5, 0x00, 0x00, 0xff },
{ 6, 0x00, 0x5f, 0x00 }, { 7, 0x00, 0x5f, 0x5f },
{ 8, 0x00, 0x5f, 0x87 }, { 9, 0x00, 0x5f, 0xaf },
{ 10, 0x00, 0x5f, 0xd7 }, { 11, 0x00, 0x5f, 0xff },
{ 12, 0x00, 0x87, 0x00 }, { 13, 0x00, 0x87, 0x5f },
{ 14, 0x00, 0x87, 0x87 }, { 15, 0x00, 0x87, 0xaf },
{ 16, 0x00, 0x87, 0xd7 }, { 17, 0x00, 0x87, 0xff },
{ 18, 0x00, 0xaf, 0x00 }, { 19, 0x00, 0xaf, 0x5f },
{ 20, 0x00, 0xaf, 0x87 }, { 21, 0x00, 0xaf, 0xaf },
{ 22, 0x00, 0xaf, 0xd7 }, { 23, 0x00, 0xaf, 0xff },
{ 24, 0x00, 0xd7, 0x00 }, { 25, 0x00, 0xd7, 0x5f },
{ 26, 0x00, 0xd7, 0x87 }, { 27, 0x00, 0xd7, 0xaf },
{ 28, 0x00, 0xd7, 0xd7 }, { 29, 0x00, 0xd7, 0xff },
{ 30, 0x00, 0xff, 0x00 }, { 31, 0x00, 0xff, 0x5f },
{ 32, 0x00, 0xff, 0x87 }, { 33, 0x00, 0xff, 0xaf },
{ 34, 0x00, 0xff, 0xd7 }, { 35, 0x00, 0xff, 0xff },
{ 216, 0x08, 0x08, 0x08 }, { 217, 0x12, 0x12, 0x12 },
{ 218, 0x1c, 0x1c, 0x1c }, { 219, 0x26, 0x26, 0x26 },
{ 220, 0x30, 0x30, 0x30 }, { 221, 0x3a, 0x3a, 0x3a },
{ 222, 0x44, 0x44, 0x44 }, { 223, 0x4e, 0x4e, 0x4e },
{ 224, 0x58, 0x58, 0x58 }, { 36, 0x5f, 0x00, 0x00 },
{ 37, 0x5f, 0x00, 0x5f }, { 38, 0x5f, 0x00, 0x87 },
{ 39, 0x5f, 0x00, 0xaf }, { 40, 0x5f, 0x00, 0xd7 },
{ 41, 0x5f, 0x00, 0xff }, { 42, 0x5f, 0x5f, 0x00 },
{ 43, 0x5f, 0x5f, 0x5f }, { 44, 0x5f, 0x5f, 0x87 },
{ 45, 0x5f, 0x5f, 0xaf }, { 46, 0x5f, 0x5f, 0xd7 },
{ 47, 0x5f, 0x5f, 0xff }, { 48, 0x5f, 0x87, 0x00 },
{ 49, 0x5f, 0x87, 0x5f }, { 50, 0x5f, 0x87, 0x87 },
{ 51, 0x5f, 0x87, 0xaf }, { 52, 0x5f, 0x87, 0xd7 },
{ 53, 0x5f, 0x87, 0xff }, { 54, 0x5f, 0xaf, 0x00 },
{ 55, 0x5f, 0xaf, 0x5f }, { 56, 0x5f, 0xaf, 0x87 },
{ 57, 0x5f, 0xaf, 0xaf }, { 58, 0x5f, 0xaf, 0xd7 },
{ 59, 0x5f, 0xaf, 0xff }, { 60, 0x5f, 0xd7, 0x00 },
{ 61, 0x5f, 0xd7, 0x5f }, { 62, 0x5f, 0xd7, 0x87 },
{ 63, 0x5f, 0xd7, 0xaf }, { 64, 0x5f, 0xd7, 0xd7 },
{ 65, 0x5f, 0xd7, 0xff }, { 66, 0x5f, 0xff, 0x00 },
{ 67, 0x5f, 0xff, 0x5f }, { 68, 0x5f, 0xff, 0x87 },
{ 69, 0x5f, 0xff, 0xaf }, { 70, 0x5f, 0xff, 0xd7 },
{ 71, 0x5f, 0xff, 0xff }, { 225, 0x62, 0x62, 0x62 },
{ 226, 0x6c, 0x6c, 0x6c }, { 227, 0x76, 0x76, 0x76 },
{ 228, 0x80, 0x80, 0x80 }, { 72, 0x87, 0x00, 0x00 },
{ 73, 0x87, 0x00, 0x5f }, { 74, 0x87, 0x00, 0x87 },
{ 75, 0x87, 0x00, 0xaf }, { 76, 0x87, 0x00, 0xd7 },
{ 77, 0x87, 0x00, 0xff }, { 78, 0x87, 0x5f, 0x00 },
{ 79, 0x87, 0x5f, 0x5f }, { 80, 0x87, 0x5f, 0x87 },
{ 81, 0x87, 0x5f, 0xaf }, { 82, 0x87, 0x5f, 0xd7 },
{ 83, 0x87, 0x5f, 0xff }, { 84, 0x87, 0x87, 0x00 },
{ 85, 0x87, 0x87, 0x5f }, { 86, 0x87, 0x87, 0x87 },
{ 87, 0x87, 0x87, 0xaf }, { 88, 0x87, 0x87, 0xd7 },
{ 89, 0x87, 0x87, 0xff }, { 90, 0x87, 0xaf, 0x00 },
{ 91, 0x87, 0xaf, 0x5f }, { 92, 0x87, 0xaf, 0x87 },
{ 93, 0x87, 0xaf, 0xaf }, { 94, 0x87, 0xaf, 0xd7 },
{ 95, 0x87, 0xaf, 0xff }, { 96, 0x87, 0xd7, 0x00 },
{ 97, 0x87, 0xd7, 0x5f }, { 98, 0x87, 0xd7, 0x87 },
{ 99, 0x87, 0xd7, 0xaf }, { 100, 0x87, 0xd7, 0xd7 },
{ 101, 0x87, 0xd7, 0xff }, { 102, 0x87, 0xff, 0x00 },
{ 103, 0x87, 0xff, 0x5f }, { 104, 0x87, 0xff, 0x87 },
{ 105, 0x87, 0xff, 0xaf }, { 106, 0x87, 0xff, 0xd7 },
{ 107, 0x87, 0xff, 0xff }, { 229, 0x8a, 0x8a, 0x8a },
{ 230, 0x94, 0x94, 0x94 }, { 231, 0x9e, 0x9e, 0x9e },
{ 232, 0xa8, 0xa8, 0xa8 }, { 108, 0xaf, 0x00, 0x00 },
{ 109, 0xaf, 0x00, 0x5f }, { 110, 0xaf, 0x00, 0x87 },
{ 111, 0xaf, 0x00, 0xaf }, { 112, 0xaf, 0x00, 0xd7 },
{ 113, 0xaf, 0x00, 0xff }, { 114, 0xaf, 0x5f, 0x00 },
{ 115, 0xaf, 0x5f, 0x5f }, { 116, 0xaf, 0x5f, 0x87 },
{ 117, 0xaf, 0x5f, 0xaf }, { 118, 0xaf, 0x5f, 0xd7 },
{ 119, 0xaf, 0x5f, 0xff }, { 120, 0xaf, 0x87, 0x00 },
{ 121, 0xaf, 0x87, 0x5f }, { 122, 0xaf, 0x87, 0x87 },
{ 123, 0xaf, 0x87, 0xaf }, { 124, 0xaf, 0x87, 0xd7 },
{ 125, 0xaf, 0x87, 0xff }, { 126, 0xaf, 0xaf, 0x00 },
{ 127, 0xaf, 0xaf, 0x5f }, { 128, 0xaf, 0xaf, 0x87 },
{ 129, 0xaf, 0xaf, 0xaf }, { 130, 0xaf, 0xaf, 0xd7 },
{ 131, 0xaf, 0xaf, 0xff }, { 132, 0xaf, 0xd7, 0x00 },
{ 133, 0xaf, 0xd7, 0x5f }, { 134, 0xaf, 0xd7, 0x87 },
{ 135, 0xaf, 0xd7, 0xaf }, { 136, 0xaf, 0xd7, 0xd7 },
{ 137, 0xaf, 0xd7, 0xff }, { 138, 0xaf, 0xff, 0x00 },
{ 139, 0xaf, 0xff, 0x5f }, { 140, 0xaf, 0xff, 0x87 },
{ 141, 0xaf, 0xff, 0xaf }, { 142, 0xaf, 0xff, 0xd7 },
{ 143, 0xaf, 0xff, 0xff }, { 233, 0xb2, 0xb2, 0xb2 },
{ 234, 0xbc, 0xbc, 0xbc }, { 235, 0xc6, 0xc6, 0xc6 },
{ 236, 0xd0, 0xd0, 0xd0 }, { 144, 0xd7, 0x00, 0x00 },
{ 145, 0xd7, 0x00, 0x5f }, { 146, 0xd7, 0x00, 0x87 },
{ 147, 0xd7, 0x00, 0xaf }, { 148, 0xd7, 0x00, 0xd7 },
{ 149, 0xd7, 0x00, 0xff }, { 150, 0xd7, 0x5f, 0x00 },
{ 151, 0xd7, 0x5f, 0x5f }, { 152, 0xd7, 0x5f, 0x87 },
{ 153, 0xd7, 0x5f, 0xaf }, { 154, 0xd7, 0x5f, 0xd7 },
{ 155, 0xd7, 0x5f, 0xff }, { 156, 0xd7, 0x87, 0x00 },
{ 157, 0xd7, 0x87, 0x5f }, { 158, 0xd7, 0x87, 0x87 },
{ 159, 0xd7, 0x87, 0xaf }, { 160, 0xd7, 0x87, 0xd7 },
{ 161, 0xd7, 0x87, 0xff }, { 162, 0xd7, 0xaf, 0x00 },
{ 163, 0xd7, 0xaf, 0x5f }, { 164, 0xd7, 0xaf, 0x87 },
{ 165, 0xd7, 0xaf, 0xaf }, { 166, 0xd7, 0xaf, 0xd7 },
{ 167, 0xd7, 0xaf, 0xff }, { 168, 0xd7, 0xd7, 0x00 },
{ 169, 0xd7, 0xd7, 0x5f }, { 170, 0xd7, 0xd7, 0x87 },
{ 171, 0xd7, 0xd7, 0xaf }, { 172, 0xd7, 0xd7, 0xd7 },
{ 173, 0xd7, 0xd7, 0xff }, { 174, 0xd7, 0xff, 0x00 },
{ 175, 0xd7, 0xff, 0x5f }, { 176, 0xd7, 0xff, 0x87 },
{ 177, 0xd7, 0xff, 0xaf }, { 178, 0xd7, 0xff, 0xd7 },
{ 179, 0xd7, 0xff, 0xff }, { 237, 0xda, 0xda, 0xda },
{ 238, 0xe4, 0xe4, 0xe4 }, { 239, 0xee, 0xee, 0xee },
{ 180, 0xff, 0x00, 0x00 }, { 181, 0xff, 0x00, 0x5f },
{ 182, 0xff, 0x00, 0x87 }, { 183, 0xff, 0x00, 0xaf },
{ 184, 0xff, 0x00, 0xd7 }, { 185, 0xff, 0x00, 0xff },
{ 186, 0xff, 0x5f, 0x00 }, { 187, 0xff, 0x5f, 0x5f },
{ 188, 0xff, 0x5f, 0x87 }, { 189, 0xff, 0x5f, 0xaf },
{ 190, 0xff, 0x5f, 0xd7 }, { 191, 0xff, 0x5f, 0xff },
{ 192, 0xff, 0x87, 0x00 }, { 193, 0xff, 0x87, 0x5f },
{ 194, 0xff, 0x87, 0x87 }, { 195, 0xff, 0x87, 0xaf },
{ 196, 0xff, 0x87, 0xd7 }, { 197, 0xff, 0x87, 0xff },
{ 198, 0xff, 0xaf, 0x00 }, { 199, 0xff, 0xaf, 0x5f },
{ 200, 0xff, 0xaf, 0x87 }, { 201, 0xff, 0xaf, 0xaf },
{ 202, 0xff, 0xaf, 0xd7 }, { 203, 0xff, 0xaf, 0xff },
{ 204, 0xff, 0xd7, 0x00 }, { 205, 0xff, 0xd7, 0x5f },
{ 206, 0xff, 0xd7, 0x87 }, { 207, 0xff, 0xd7, 0xaf },
{ 208, 0xff, 0xd7, 0xd7 }, { 209, 0xff, 0xd7, 0xff },
{ 210, 0xff, 0xff, 0x00 }, { 211, 0xff, 0xff, 0x5f },
{ 212, 0xff, 0xff, 0x87 }, { 213, 0xff, 0xff, 0xaf },
{ 214, 0xff, 0xff, 0xd7 }, { 215, 0xff, 0xff, 0xff },
};
int colour_cmp_rgb(const void *, const void *);
/* Compare function for bsearch(). */
int
colour_cmp_rgb(const void *lhs0, const void *rhs0)
static int
colour_dist_sq(int R, int G, int B, int r, int g, int b)
{
const struct colour_rgb *lhs = lhs0, *rhs = rhs0;
if (lhs->r < rhs->r)
return (-1);
if (lhs->r > rhs->r)
return (1);
if (lhs->g < rhs->g)
return (-1);
if (lhs->g > rhs->g)
return (1);
if (lhs->b < rhs->b)
return (-1);
if (lhs->b > rhs->b)
return (1);
return (0);
return ((R - r) * (R - r) + (G - g) * (G - g) + (B - b) * (B - b));
}
/* Work out the nearest colour from the 256 colour set. */
static int
colour_to_6cube(int v)
{
if (v < 48)
return (0);
if (v < 114)
return (1);
return ((v - 35) / 40);
}
/*
* Convert an RGB triplet to the xterm(1) 256 colour palette.
*
* xterm provides a 6x6x6 colour cube (16 - 231) and 24 greys (232 - 255). We
* map our RGB colour to the closest in the cube, also work out the closest
* grey, and use the nearest of the two.
*
* Note that the xterm has much lower resolution for darker colors (they are
* not evenly spread out), so our 6 levels are not evenly spread: 0x0, 0x5f
* (95), 0x87 (135), 0xaf (175), 0xd7 (215) and 0xff (255). Greys are more
* evenly spread (8, 18, 28 ... 238).
*/
int
colour_find_rgb(u_char r, u_char g, u_char b)
{
struct colour_rgb rgb = { .r = r, .g = g, .b = b }, *found;
u_int distance, lowest, colour, i;
int dr, dg, db;
static const int q2c[6] = { 0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff };
int qr, qg, qb, cr, cg, cb, d, idx;
int grey_avg, grey_idx, grey;
found = bsearch(&rgb, colour_to_256, nitems(colour_to_256),
sizeof colour_to_256[0], colour_cmp_rgb);
if (found != NULL)
return (16 + found->i);
/* Map RGB to 6x6x6 cube. */
qr = colour_to_6cube(r); cr = q2c[qr];
qg = colour_to_6cube(g); cg = q2c[qg];
qb = colour_to_6cube(b); cb = q2c[qb];
colour = 16;
lowest = UINT_MAX;
for (i = 0; i < 240; i++) {
dr = (int)colour_from_256[i].r - r;
dg = (int)colour_from_256[i].g - g;
db = (int)colour_from_256[i].b - b;
/* If we have hit the colour exactly, return early. */
if (cr == r && cg == g && cb == b)
return ((16 + (36 * qr) + (6 * qg) + qb) | COLOUR_FLAG_256);
distance = dr * dr + dg * dg + db * db;
if (distance < lowest) {
lowest = distance;
colour = 16 + i;
}
}
return (colour);
/* Work out the closest grey (average of RGB). */
grey_avg = (r + g + b) / 3;
if (grey_avg > 238)
grey_idx = 23;
else
grey_idx = (grey_avg - 3) / 10;
grey = 8 + (10 * grey_idx);
/* Is grey or 6x6x6 colour closest? */
d = colour_dist_sq(cr, cg, cb, r, g, b);
if (colour_dist_sq(grey, grey, grey, r, g, b) < d)
idx = 232 + grey_idx;
else
idx = 16 + (36 * qr) + (6 * qg) + qb;
return (idx | COLOUR_FLAG_256);
}
/* Set grid cell foreground colour. */
void
colour_set_fg(struct grid_cell *gc, int c)
/* Join RGB into a colour. */
int
colour_join_rgb(u_char r, u_char g, u_char b)
{
if (c & 0x100)
gc->flags |= GRID_FLAG_FG256;
gc->fg = c;
return ((((int)((r) & 0xff)) << 16) |
(((int)((g) & 0xff)) << 8) |
(((int)((b) & 0xff))) | COLOUR_FLAG_RGB);
}
/* Set grid cell background colour. */
/* Split colour into RGB. */
void
colour_set_bg(struct grid_cell *gc, int c)
colour_split_rgb(int c, u_char *r, u_char *g, u_char *b)
{
if (c & 0x100)
gc->flags |= GRID_FLAG_BG256;
gc->bg = c;
*r = (c >> 16) & 0xff;
*g = (c >> 8) & 0xff;
*b = c & 0xff;
}
/* Convert colour to a string. */
@@ -359,9 +109,16 @@ const char *
colour_tostring(int c)
{
static char s[32];
u_char r, g, b;
if (c & 0x100) {
xsnprintf(s, sizeof s, "colour%d", c & ~0x100);
if (c & COLOUR_FLAG_RGB) {
colour_split_rgb(c, &r, &g, &b);
xsnprintf(s, sizeof s, "#%02x%02x%02x", r, g, b);
return (s);
}
if (c & COLOUR_FLAG_256) {
xsnprintf(s, sizeof s, "colour%u", c & 0xff);
return (s);
}
@@ -421,14 +178,14 @@ colour_fromstring(const char *s)
n = sscanf(s + 1, "%2hhx%2hhx%2hhx", &r, &g, &b);
if (n != 3)
return (-1);
return (colour_find_rgb(r, g, b) | 0x100);
return (colour_join_rgb(r, g, b));
}
if (strncasecmp(s, "colour", (sizeof "colour") - 1) == 0) {
n = strtonum(s + (sizeof "colour") - 1, 0, 255, &errstr);
if (errstr != NULL)
return (-1);
return (n | 0x100);
return (n | COLOUR_FLAG_256);
}
if (strcasecmp(s, "black") == 0 || strcmp(s, "0") == 0)

View File

@@ -35,6 +35,14 @@
#define ECHOPRT 0
#endif
#ifndef ACCESSPERMS
#define ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO)
#endif
#if !defined(FIONREAD) && defined(__sun)
#include <sys/filio.h>
#endif
#ifndef HAVE_BSD_TYPES
typedef uint8_t u_int8_t;
typedef uint16_t u_int16_t;
@@ -190,7 +198,7 @@ typedef uint64_t u_int64_t;
#ifndef HAVE_CLOSEFROM
/* closefrom.c */
void closefrom(int);
void closefrom(int);
#endif
#ifndef HAVE_STRCASESTR
@@ -223,6 +231,16 @@ size_t strlcat(char *, const char *, size_t);
int daemon(int, int);
#endif
#ifndef HAVE_GETPROGNAME
/* getprogname.c */
const char *getprogname(void);
#endif
#ifndef HAVE_SETPROCTITLE
/* setproctitle.c */
void setproctitle(const char *, ...);
#endif
#ifndef HAVE_B64_NTOP
/* b64_ntop.c */
#undef b64_ntop /* for Cygwin */
@@ -269,7 +287,14 @@ int openat(int, const char *, int, ...);
#ifndef HAVE_REALLOCARRAY
/* reallocarray.c */
void *reallocarray(void *, size_t, size_t size);
void *reallocarray(void *, size_t, size_t);
#endif
#ifdef HAVE_UTF8PROC
/* utf8proc.c */
int utf8proc_wcwidth(wchar_t);
int utf8proc_mbtowc(wchar_t *, const char *, size_t);
int utf8proc_wctomb(char *, wchar_t);
#endif
#ifdef HAVE_GETOPT

View File

@@ -84,7 +84,8 @@ BSDgetopt(int nargc, char *const *nargv, const char *ostr)
++BSDoptind;
if (BSDopterr && *ostr != ':')
(void)fprintf(stderr,
"%s: unknown option -- %c\n", __progname, BSDoptopt);
"%s: unknown option -- %c\n", getprogname(),
BSDoptopt);
return (BADCH);
}
if (*++oli != ':') { /* don't need argument */
@@ -102,7 +103,7 @@ BSDgetopt(int nargc, char *const *nargv, const char *ostr)
if (BSDopterr)
(void)fprintf(stderr,
"%s: option requires an argument -- %c\n",
__progname, BSDoptopt);
getprogname(), BSDoptopt);
return (BADCH);
}
else /* white space */

43
compat/getprogname.c Normal file
View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2016 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 "tmux.h"
#if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
const char *
getprogname(void)
{
extern char *program_invocation_short_name;
return (program_invocation_short_name);
}
#elif defined(HAVE___PROGNAME)
const char *
getprogname(void)
{
extern char *__progname;
return (__progname);
}
#else
const char *
getprogname(void)
{
return ("tmux");
}
#endif

51
compat/setproctitle.c Normal file
View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2016 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 <string.h>
#include "tmux.h"
#if defined(HAVE_PRCTL) && defined(HAVE_PR_SET_NAME)
#include <sys/prctl.h>
void
setproctitle(const char *fmt, ...)
{
char title[16], name[16], *cp;
va_list ap;
int used;
va_start(ap, fmt);
vsnprintf(title, sizeof title, fmt, ap);
va_end(ap);
used = snprintf(name, sizeof name, "%s: %s", getprogname(), title);
if (used >= (int)sizeof name) {
cp = strrchr(name, ' ');
if (cp != NULL)
*cp = '\0';
}
prctl(PR_SET_NAME, name);
}
#else
void
setproctitle(const char *fmt, ...)
{
}
#endif

70
compat/utf8proc.c Normal file
View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2016 Joshua Rubin <joshua@rubixconsulting.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 <utf8proc.h>
#include "tmux.h"
int
utf8proc_wcwidth(wchar_t wc)
{
int cat;
cat = utf8proc_category(wc);
if (cat == UTF8PROC_CATEGORY_CO) {
/*
* The private use category is where powerline and similar
* codepoints are stored, they have "ambiguous" width - use 1.
*/
return (1);
}
if (cat == UTF8PROC_CATEGORY_SO) {
/* Symbols, like emoji, should always use width 1. */
return (1);
}
return (utf8proc_charwidth(wc));
}
int
utf8proc_mbtowc(wchar_t *pwc, const char *s, size_t n)
{
utf8proc_ssize_t slen;
if (s == NULL)
return (0);
/*
* *pwc == -1 indicates invalid codepoint
* slen < 0 indicates an error
*/
slen = utf8proc_iterate(s, n, pwc);
if (*pwc == (wchar_t)-1 || slen < 0)
return (-1);
return (slen);
}
int
utf8proc_wctomb(char *s, wchar_t wc)
{
if (s == NULL)
return (0);
if (!utf8proc_codepoint_valid(wc))
return (-1);
return (utf8proc_encode_char(wc, s));
}

View File

@@ -1,6 +1,6 @@
# configure.ac
AC_INIT(tmux, 2.2)
AC_INIT(tmux, 2.3)
AC_CONFIG_AUX_DIR(etc)
AM_INIT_AUTOMAKE([foreign subdir-objects])
@@ -40,6 +40,14 @@ AC_ARG_ENABLE(
)
AM_CONDITIONAL(IS_COVERAGE, test "x$found_coverage" = xyes)
# Is this --enable-profile?
AC_ARG_ENABLE(
profile,
AC_HELP_STRING(--enable-profile, enable profile build flags),
found_profile=$enable_profile
)
AM_CONDITIONAL(IS_PROFILE, test "x$found_profile" = xyes)
# Is this a static build?
AC_ARG_ENABLE(
static,
@@ -48,7 +56,7 @@ AC_ARG_ENABLE(
)
if test "x$found_static" = xyes; then
LDFLAGS="$LDFLAGS -static"
PKG_CONFIG="pkg-config --static"
test "x$PKG_CONFIG" != x && PKG_CONFIG="$PKG_CONFIG --static"
fi
# Is this gcc?
@@ -87,12 +95,10 @@ AC_MSG_RESULT($found_glibc)
AC_CHECK_HEADERS(
[ \
bitstring.h \
curses.h \
dirent.h \
fcntl.h \
inttypes.h \
libutil.h \
ncurses.h \
ndir.h \
paths.h \
pty.h \
@@ -113,7 +119,7 @@ AC_CHECK_FUNCS(
[ \
dirfd \
flock \
setproctitle \
prctl \
sysconf \
cfmakeraw \
]
@@ -140,30 +146,60 @@ PKG_CHECK_MODULES(
)
]
)
AC_CHECK_HEADER(
event.h,
,
found_libevent=no
)
if test "x$found_libevent" = xno; then
AC_MSG_ERROR("libevent not found")
fi
# Look for ncurses
# Look for ncurses.
PKG_CHECK_MODULES(
LIBNCURSES,
ncurses,
[
CPPFLAGS="$LIBNCURSES_CFLAGS $CPPFLAGS"
LIBS="$LIBNCURSES_LIBS $LIBS"
found_curses=yes
found_ncurses=yes
],
[
AC_SEARCH_LIBS(
setupterm,
[ncurses curses terminfo],
found_curses=yes,
found_curses=no
)
]
found_ncurses=no
)
if test "x$found_curses" = xno; then
AC_MSG_ERROR("curses not found")
if test "x$found_ncurses" = xno; then
# pkg-config didn't work, try ncurses.
AC_CHECK_LIB(
ncurses,
setupterm,
found_ncurses=yes,
found_ncurses=no
)
AC_CHECK_HEADER(
ncurses.h,
,
found_ncurses=no)
fi
if test "x$found_ncurses" = xyes; then
LIBS="$LIBS -lncurses"
AC_DEFINE(HAVE_NCURSES_H)
else
# No ncurses, try curses.
AC_CHECK_LIB(
curses,
setupterm,
found_curses=yes,
found_curses=no
)
AC_CHECK_HEADER(
curses.h,
,
found_curses=no)
if test "x$found_curses" = xyes; then
LIBS="$LIBS -lcurses"
AC_DEFINE(HAVE_CURSES_H)
else
AC_MSG_ERROR("curses or ncurses not found")
fi
fi
# Look for utempter.
@@ -188,6 +224,29 @@ if test "x$found_utempter" = xyes; then
fi
fi
# Look for utf8proc.
AC_ARG_ENABLE(
utf8proc,
AC_HELP_STRING(--enable-utf8proc, use utf8proc if it is installed),
found_utf8proc=$enable_utf8proc,
found_utf8proc=no
)
if test "x$found_utf8proc" = xyes; then
AC_CHECK_HEADER(utf8proc.h, found_utf8proc=yes, found_utf8proc=no)
if test "x$found_utf8proc" = xyes; then
AC_SEARCH_LIBS(
utf8proc_charwidth,
utf8proc,
found_utf8proc=yes,
found_utf8proc=no
)
if test "x$found_utf8proc" = xyes; then
AC_DEFINE(HAVE_UTF8PROC)
fi
fi
fi
AM_CONDITIONAL(HAVE_UTF8PROC, [test "x$found_utf8proc" = xyes])
# Check for b64_ntop.
AC_MSG_CHECKING(for b64_ntop)
AC_TRY_LINK(
@@ -298,6 +357,20 @@ if test "x$found_daemon" = xyes; then
fi
AM_CONDITIONAL(NO_DAEMON, [test "x$found_daemon" = xno])
# Look for getprogname, compat/getprogname.c used if missing.
AC_CHECK_FUNC(getprogname, found_getprogname=yes, found_getprogname=no)
if test "x$found_getprogname" = xyes; then
AC_DEFINE(HAVE_GETPROGNAME)
fi
AM_CONDITIONAL(NO_GETPROGNAME, [test "x$found_getprogname" = xno])
# Look for setproctitle, compat/setproctitle.c used if missing.
AC_CHECK_FUNC(setproctitle, found_setproctitle=yes, found_setproctitle=no)
if test "x$found_setproctitle" = xyes; then
AC_DEFINE(HAVE_SETPROCTITLE)
fi
AM_CONDITIONAL(NO_SETPROCTITLE, [test "x$found_setproctitle" = xno])
# Look for setenv, compat/setenv.c used if missing.
AC_CHECK_FUNC(setenv, found_setenv=yes, found_setenv=no)
if test "x$found_setenv" = xyes; then
@@ -475,6 +548,31 @@ AC_LINK_IFELSE([AC_LANG_SOURCE(
AC_MSG_RESULT(no)
)
# Look for program_invocation_short_name.
AC_MSG_CHECKING(for program_invocation_short_name)
AC_LINK_IFELSE([AC_LANG_SOURCE(
[
#include <stdio.h>
#include <stdlib.h>
extern char *program_invocation_short_name;
int main(void) {
const char *cp = program_invocation_short_name;
printf("%s\n", cp);
exit(0);
}
])],
[AC_DEFINE(HAVE_PROGRAM_INVOCATION_SHORT_NAME) AC_MSG_RESULT(yes)],
AC_MSG_RESULT(no)
)
# Look for prctl(PR_SET_NAME).
AC_CHECK_DECL(
PR_SET_NAME,
AC_DEFINE(HAVE_PR_SET_NAME),
,
[#include <sys/prctl.h>]
)
# Look for fcntl(F_CLOSEM).
AC_CHECK_DECL(
F_CLOSEM,

View File

@@ -195,19 +195,25 @@ environ_update(const char *vars, struct environ *srcenv,
void
environ_push(struct environ *env)
{
struct environ_entry *envent;
char *v;
while (*environ != NULL) {
v = xstrdup(*environ);
v[strcspn(v, "=")] = '\0';
unsetenv(v);
free(v);
}
struct environ_entry *envent;
environ = xcalloc(1, sizeof *environ);
RB_FOREACH(envent, environ, env) {
if (envent->value != NULL)
if (envent->value != NULL && *envent->name != '\0')
setenv(envent->name, envent->value, 1);
}
}
/* Log the environment. */
void
environ_log(struct environ *env, const char *prefix)
{
struct environ_entry *envent;
RB_FOREACH(envent, environ, env) {
if (envent->value != NULL && *envent->name != '\0') {
log_debug("%s%s=%s", prefix, envent->name,
envent->value);
}
}
}

View File

@@ -485,6 +485,7 @@ struct format_tree *
format_create(struct cmd_q *cmdq, int flags)
{
struct format_tree *ft;
struct cmd *cmd;
if (!event_initialized(&format_job_event)) {
evtimer_set(&format_job_event, format_job_timer, NULL);
@@ -503,6 +504,10 @@ format_create(struct cmd_q *cmdq, int flags)
if (cmdq != NULL && cmdq->cmd != NULL)
format_add(ft, "command_name", "%s", cmdq->cmd->entry->name);
if (cmdq != NULL && cmdq->parent != NULL) {
cmd = cmdq->parent->cmd;
format_add(ft, "command_hooked", "%s", cmd->entry->name);
}
return (ft);
}
@@ -862,27 +867,18 @@ fail:
char *
format_expand_time(struct format_tree *ft, const char *fmt, time_t t)
{
char *tmp, *expanded;
size_t tmplen;
struct tm *tm;
char s[2048];
if (fmt == NULL || *fmt == '\0')
return (xstrdup(""));
tm = localtime(&t);
tmp = NULL;
tmplen = strlen(fmt);
if (strftime(s, sizeof s, fmt, tm) == 0)
return (xstrdup(""));
do {
tmp = xreallocarray(tmp, 2, tmplen);
tmplen *= 2;
} while (strftime(tmp, tmplen, fmt, tm) == 0);
expanded = format_expand(ft, tmp);
free(tmp);
return (expanded);
return (format_expand(ft, s));
}
/* Expand keys in a template. */

View File

@@ -67,6 +67,7 @@ grid_view_clear_history(struct grid *gd)
grid_collect_history(gd);
grid_scroll_history(gd);
}
gd->hscrolled = 0;
}
/* Clear area. */

85
grid.c
View File

@@ -37,14 +37,12 @@
/* Default grid cell data. */
const struct grid_cell grid_default_cell = {
0, 0, { .fg = 8 }, { .bg = 8 }, { { ' ' }, 0, 1, 1 }
0, 0, 8, 8, { { ' ' }, 0, 1, 1 }
};
const struct grid_cell_entry grid_default_entry = {
0, { .data = { 0, 8, 8, ' ' } }
};
int grid_check_y(struct grid *, u_int);
void grid_reflow_copy(struct grid_line *, u_int, struct grid_line *l,
u_int, u_int);
void grid_reflow_join(struct grid *, u_int *, struct grid_line *, u_int);
@@ -64,7 +62,7 @@ grid_clear_cell(struct grid *gd, u_int px, u_int py)
}
/* Check grid y position. */
int
static int
grid_check_y(struct grid *gd, u_int py)
{
if ((py) >= (gd)->hsize + (gd)->sy) {
@@ -74,6 +72,21 @@ grid_check_y(struct grid *gd, u_int py)
return (0);
}
/* Compare grid cells. Return 1 if equal, 0 if not. */
int
grid_cells_equal(const struct grid_cell *gca, const struct grid_cell *gcb)
{
if (gca->fg != gcb->fg || gca->bg != gcb->bg)
return (0);
if (gca->attr != gcb->attr || gca->flags != gcb->flags)
return (0);
if (gca->data.width != gcb->data.width)
return (0);
if (gca->data.size != gcb->data.size)
return (0);
return (memcmp(gca->data.data, gcb->data.data, gca->data.size) == 0);
}
/* Create a new grid. */
struct grid *
grid_create(u_int sx, u_int sy, u_int hlimit)
@@ -86,6 +99,7 @@ grid_create(u_int sx, u_int sy, u_int hlimit)
gd->flags = GRID_HISTORY;
gd->hscrolled = 0;
gd->hsize = 0;
gd->hlimit = hlimit;
@@ -131,7 +145,7 @@ grid_compare(struct grid *ga, struct grid *gb)
for (xx = 0; xx < gla->cellsize; xx++) {
grid_get_cell(ga, xx, yy, &gca);
grid_get_cell(gb, xx, yy, &gcb);
if (memcmp(&gca, &gcb, sizeof (struct grid_cell)) != 0)
if (!grid_cells_equal(&gca, &gcb))
return (1);
}
}
@@ -157,6 +171,8 @@ grid_collect_history(struct grid *gd)
grid_move_lines(gd, 0, yy, gd->hsize + gd->sy - yy);
gd->hsize -= yy;
if (gd->hscrolled > gd->hsize)
gd->hscrolled = gd->hsize;
}
/*
@@ -173,6 +189,7 @@ grid_scroll_history(struct grid *gd)
sizeof *gd->linedata);
memset(&gd->linedata[yy], 0, sizeof gd->linedata[yy]);
gd->hscrolled++;
gd->hsize++;
}
@@ -183,7 +200,9 @@ grid_clear_history(struct grid *gd)
grid_clear_lines(gd, 0, gd->hsize);
grid_move_lines(gd, 0, gd->hsize, gd->sy);
gd->hscrolled = 0;
gd->hsize = 0;
gd->linedata = xreallocarray(gd->linedata, gd->sy,
sizeof *gd->linedata);
}
@@ -218,6 +237,7 @@ grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower)
memset(gl_lower, 0, sizeof *gl_lower);
/* Move the history offset down over the line. */
gd->hscrolled++;
gd->hsize++;
}
@@ -270,10 +290,14 @@ grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
return;
}
gc->flags = gce->flags & ~GRID_FLAG_EXTENDED;
gc->flags = gce->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
gc->attr = gce->data.attr;
gc->fg = gce->data.fg;
if (gce->flags & GRID_FLAG_FG256)
gc->fg |= COLOUR_FLAG_256;
gc->bg = gce->data.bg;
if (gce->flags & GRID_FLAG_BG256)
gc->bg |= COLOUR_FLAG_256;
utf8_set(&gc->data, gce->data.data);
}
@@ -297,9 +321,12 @@ grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
extended = (gce->flags & GRID_FLAG_EXTENDED);
if (!extended && (gc->data.size != 1 || gc->data.width != 1))
extended = 1;
if (!extended && (gc->flags & (GRID_FLAG_FGRGB|GRID_FLAG_BGRGB)))
if (!extended && ((gc->fg & COLOUR_FLAG_RGB) ||
(gc->bg & COLOUR_FLAG_RGB)))
extended = 1;
if (extended) {
gl->flags |= GRID_LINE_EXTENDED;
if (~gce->flags & GRID_FLAG_EXTENDED) {
gl->extddata = xreallocarray(gl->extddata,
gl->extdsize + 1, sizeof *gl->extddata);
@@ -314,10 +341,14 @@ grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
return;
}
gce->flags = gc->flags & ~GRID_FLAG_EXTENDED;
gce->flags = gc->flags;
gce->data.attr = gc->attr;
gce->data.fg = gc->fg;
gce->data.bg = gc->bg;
gce->data.fg = gc->fg & 0xff;
if (gc->fg & COLOUR_FLAG_256)
gce->flags |= GRID_FLAG_FG256;
gce->data.bg = gc->bg & 0xff;
if (gc->bg & COLOUR_FLAG_256)
gce->flags |= GRID_FLAG_BG256;
gce->data.data = gc->data.data[0];
}
@@ -446,18 +477,20 @@ size_t
grid_string_cells_fg(const struct grid_cell *gc, int *values)
{
size_t n;
u_char r, g, b;
n = 0;
if (gc->flags & GRID_FLAG_FG256) {
if (gc->fg & COLOUR_FLAG_256) {
values[n++] = 38;
values[n++] = 5;
values[n++] = gc->fg;
} else if (gc->flags & GRID_FLAG_FGRGB) {
values[n++] = gc->fg & 0xff;
} else if (gc->fg & COLOUR_FLAG_RGB) {
values[n++] = 38;
values[n++] = 2;
values[n++] = gc->fg_rgb.r;
values[n++] = gc->fg_rgb.g;
values[n++] = gc->fg_rgb.b;
colour_split_rgb(gc->fg, &r, &g, &b);
values[n++] = r;
values[n++] = g;
values[n++] = b;
} else {
switch (gc->fg) {
case 0:
@@ -493,18 +526,20 @@ size_t
grid_string_cells_bg(const struct grid_cell *gc, int *values)
{
size_t n;
u_char r, g, b;
n = 0;
if (gc->flags & GRID_FLAG_BG256) {
if (gc->bg & COLOUR_FLAG_256) {
values[n++] = 48;
values[n++] = 5;
values[n++] = gc->bg;
} else if (gc->flags & GRID_FLAG_BGRGB) {
values[n++] = gc->bg & 0xff;
} else if (gc->bg & COLOUR_FLAG_RGB) {
values[n++] = 48;
values[n++] = 2;
values[n++] = gc->bg_rgb.r;
values[n++] = gc->bg_rgb.g;
values[n++] = gc->bg_rgb.b;
colour_split_rgb(gc->bg, &r, &g, &b);
values[n++] = r;
values[n++] = g;
values[n++] = b;
} else {
switch (gc->bg) {
case 0:
@@ -525,7 +560,7 @@ grid_string_cells_bg(const struct grid_cell *gc, int *values)
case 102:
case 103:
case 104:
case 105:
case 105:
case 106:
case 107:
values[n++] = gc->bg - 10;
@@ -886,6 +921,10 @@ grid_reflow(struct grid *dst, struct grid *src, u_int new_x)
grid_reflow_join(dst, &py, src_gl, new_x);
}
previous_wrapped = (src_gl->flags & GRID_LINE_WRAPPED);
/* This is where we started scrolling. */
if (line == sy + src->hsize - src->hscrolled - 1)
dst->hscrolled = 0;
}
grid_destroy(src);

45
input.c
View File

@@ -961,7 +961,7 @@ input_reply(struct input_ctx *ictx, const char *fmt, ...)
char *reply;
va_start(ap, fmt);
vasprintf(&reply, fmt, ap);
xvasprintf(&reply, fmt, ap);
va_end(ap);
bufferevent_write(ictx->wp->event, reply, strlen(reply));
@@ -1628,23 +1628,15 @@ input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
(*i)++;
c = input_get(ictx, *i, 0, -1);
if (c == -1) {
if (fgbg == 38) {
gc->flags &= ~(GRID_FLAG_FG256|GRID_FLAG_FGRGB);
if (fgbg == 38)
gc->fg = 8;
} else if (fgbg == 48) {
gc->flags &= ~(GRID_FLAG_BG256|GRID_FLAG_BGRGB);
else if (fgbg == 48)
gc->bg = 8;
}
} else {
if (fgbg == 38) {
gc->flags |= GRID_FLAG_FG256;
gc->flags &= ~GRID_FLAG_FGRGB;
gc->fg = c;
} else if (fgbg == 48) {
gc->flags |= GRID_FLAG_BG256;
gc->flags &= ~GRID_FLAG_BGRGB;
gc->bg = c;
}
if (fgbg == 38)
gc->fg = c | COLOUR_FLAG_256;
else if (fgbg == 48)
gc->bg = c | COLOUR_FLAG_256;
}
}
@@ -1668,19 +1660,10 @@ input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
if (b == -1 || b > 255)
return;
if (fgbg == 38) {
gc->flags &= ~GRID_FLAG_FG256;
gc->flags |= GRID_FLAG_FGRGB;
gc->fg_rgb.r = r;
gc->fg_rgb.g = g;
gc->fg_rgb.b = b;
} else if (fgbg == 48) {
gc->flags &= ~GRID_FLAG_BG256;
gc->flags |= GRID_FLAG_BGRGB;
gc->bg_rgb.r = r;
gc->bg_rgb.g = g;
gc->bg_rgb.b = b;
}
if (fgbg == 38)
gc->fg = colour_join_rgb(r, g, b);
else if (fgbg == 48)
gc->bg = colour_join_rgb(r, g, b);
}
/* Handle CSI SGR. */
@@ -1761,11 +1744,9 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
case 35:
case 36:
case 37:
gc->flags &= ~(GRID_FLAG_FG256|GRID_FLAG_FGRGB);
gc->fg = n - 30;
break;
case 39:
gc->flags &= ~(GRID_FLAG_FG256|GRID_FLAG_FGRGB);
gc->fg = 8;
break;
case 40:
@@ -1776,11 +1757,9 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
case 45:
case 46:
case 47:
gc->flags &= ~(GRID_FLAG_BG256|GRID_FLAG_BGRGB);
gc->bg = n - 40;
break;
case 49:
gc->flags &= ~(GRID_FLAG_BG256|GRID_FLAG_BGRGB);
gc->bg = 8;
break;
case 90:
@@ -1791,7 +1770,6 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
case 95:
case 96:
case 97:
gc->flags &= ~(GRID_FLAG_FG256|GRID_FLAG_FGRGB);
gc->fg = n;
break;
case 100:
@@ -1802,7 +1780,6 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
case 105:
case 106:
case 107:
gc->flags &= ~(GRID_FLAG_BG256|GRID_FLAG_BGRGB);
gc->bg = n - 10;
break;
}

View File

@@ -146,8 +146,7 @@ key_string_lookup_string(const char *string)
{
static const char *other = "!#()+,-.0123456789:;<=>?'\r\t";
key_code key;
u_short u;
int size;
u_int u;
key_code modifiers;
struct utf8_data ud;
u_int i;
@@ -160,7 +159,9 @@ key_string_lookup_string(const char *string)
/* Is this a hexadecimal value? */
if (string[0] == '0' && string[1] == 'x') {
if (sscanf(string + 2, "%hx%n", &u, &size) != 1 || size > 4)
if (sscanf(string + 2, "%x", &u) != 1)
return (KEYC_UNKNOWN);
if (u > 0x1fffff)
return (KEYC_UNKNOWN);
return (u);
}
@@ -226,6 +227,7 @@ key_string_lookup_key(key_code key)
char tmp[8];
u_int i;
struct utf8_data ud;
size_t off;
*out = '\0';
@@ -270,8 +272,9 @@ key_string_lookup_key(key_code key)
/* Is this a UTF-8 key? */
if (key > 127 && key < KEYC_BASE) {
if (utf8_split(key, &ud) == UTF8_DONE) {
memcpy(out, ud.data, ud.size);
out[ud.size] = '\0';
off = strlen(out);
memcpy(out + off, ud.data, ud.size);
out[off + ud.size] = '\0';
return (out);
}
}

View File

@@ -23,14 +23,17 @@
#include "tmux.h"
struct layout_cell *layout_find_bottomright(struct layout_cell *);
u_short layout_checksum(const char *);
int layout_append(struct layout_cell *, char *, size_t);
struct layout_cell *layout_construct(struct layout_cell *, const char **);
void layout_assign(struct window_pane **, struct layout_cell *);
static struct layout_cell *layout_find_bottomright(struct layout_cell *);
static u_short layout_checksum(const char *);
static int layout_append(struct layout_cell *, char *,
size_t);
static struct layout_cell *layout_construct(struct layout_cell *,
const char **);
static void layout_assign(struct window_pane **,
struct layout_cell *);
/* Find the bottom-right cell. */
struct layout_cell *
static struct layout_cell *
layout_find_bottomright(struct layout_cell *lc)
{
if (lc->type == LAYOUT_WINDOWPANE)
@@ -40,7 +43,7 @@ layout_find_bottomright(struct layout_cell *lc)
}
/* Calculate layout checksum. */
u_short
static u_short
layout_checksum(const char *layout)
{
u_short csum;
@@ -63,12 +66,12 @@ layout_dump(struct layout_cell *root)
if (layout_append(root, layout, sizeof layout) != 0)
return (NULL);
xasprintf(&out, "%04x,%s", layout_checksum(layout), layout);
xasprintf(&out, "%04hx,%s", layout_checksum(layout), layout);
return (out);
}
/* Append information for a single cell. */
int
static int
layout_append(struct layout_cell *lc, char *buf, size_t len)
{
struct layout_cell *lcchild;
@@ -147,7 +150,7 @@ layout_parse(struct window *w, const char *layout)
/* Fewer panes than cells - close the bottom right. */
lcchild = layout_find_bottomright(lc);
layout_destroy_cell(lcchild, &lc);
layout_destroy_cell(w, lcchild, &lc);
}
/* Save the old window size and resize to the layout size. */
@@ -182,7 +185,7 @@ fail:
}
/* Assign panes into cells. */
void
static void
layout_assign(struct window_pane **wp, struct layout_cell *lc)
{
struct layout_cell *lcchild;
@@ -201,7 +204,7 @@ layout_assign(struct window_pane **wp, struct layout_cell *lc)
}
/* Construct a cell from all or part of a layout tree. */
struct layout_cell *
static struct layout_cell *
layout_construct(struct layout_cell *lcparent, const char **layout)
{
struct layout_cell *lc, *lcchild;

View File

@@ -155,7 +155,8 @@ layout_set_even_h(struct window *w)
/* Allocate any remaining space. */
if (w->sx > xoff - 1) {
lc = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(lc, LAYOUT_LEFTRIGHT, w->sx - (xoff - 1));
layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT,
w->sx - (xoff - 1));
}
/* Fix cell offsets. */
@@ -208,7 +209,8 @@ layout_set_even_v(struct window *w)
/* Allocate any remaining space. */
if (w->sy > yoff - 1) {
lc = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(lc, LAYOUT_TOPBOTTOM, w->sy - (yoff - 1));
layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM,
w->sy - (yoff - 1));
}
/* Fix cell offsets. */
@@ -322,14 +324,16 @@ layout_set_main_h(struct window *w)
if (w->sx <= used)
continue;
lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
layout_resize_adjust(lcchild, LAYOUT_LEFTRIGHT, w->sx - used);
layout_resize_adjust(w, lcchild, LAYOUT_LEFTRIGHT,
w->sx - used);
}
/* Adjust the last row height to fit if necessary. */
used = mainheight + (rows * height) + rows - 1;
if (w->sy > used) {
lcrow = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used);
layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM,
w->sy - used);
}
/* Fix cell offsets. */
@@ -443,14 +447,16 @@ layout_set_main_v(struct window *w)
if (w->sy <= used)
continue;
lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells);
layout_resize_adjust(lcchild, LAYOUT_TOPBOTTOM, w->sy - used);
layout_resize_adjust(w, lcchild, LAYOUT_TOPBOTTOM,
w->sy - used);
}
/* Adjust the last column width to fit if necessary. */
used = mainwidth + (columns * width) + columns - 1;
if (w->sx > used) {
lccolumn = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(lccolumn, LAYOUT_LEFTRIGHT, w->sx - used);
layout_resize_adjust(w, lccolumn, LAYOUT_LEFTRIGHT,
w->sx - used);
}
/* Fix cell offsets. */
@@ -543,14 +549,16 @@ layout_set_tiled(struct window *w)
if (w->sx <= used)
continue;
lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
layout_resize_adjust(lcchild, LAYOUT_LEFTRIGHT, w->sx - used);
layout_resize_adjust(w, lcchild, LAYOUT_LEFTRIGHT,
w->sx - used);
}
/* Adjust the last row height to fit if necessary. */
used = (rows * height) + rows - 1;
if (w->sy > used) {
lcrow = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used);
layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM,
w->sy - used);
}
/* Fix cell offsets. */

417
layout.c
View File

@@ -2,6 +2,7 @@
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2016 Stephen Kent <smkent@smkent.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -32,8 +33,20 @@
* cell a pointer to its parent cell.
*/
int layout_resize_pane_grow(struct layout_cell *, enum layout_type, int);
int layout_resize_pane_shrink(struct layout_cell *, enum layout_type, int);
static u_int layout_resize_check(struct window *, struct layout_cell *,
enum layout_type);
static int layout_resize_pane_grow(struct window *, struct layout_cell *,
enum layout_type, int);
static int layout_resize_pane_shrink(struct window *, struct layout_cell *,
enum layout_type, int);
static int layout_need_status(struct layout_cell *, int);
static u_int layout_new_pane_size(struct window *, u_int,
struct layout_cell *, enum layout_type, u_int, u_int,
u_int);
static int layout_set_size_check(struct window *, struct layout_cell *,
enum layout_type, int);
static void layout_resize_child_cells(struct window *,
struct layout_cell *);
struct layout_cell *
layout_create_cell(struct layout_cell *lcparent)
@@ -163,6 +176,30 @@ layout_fix_offsets(struct layout_cell *lc)
}
}
/*
* Returns 1 if we need to reserve space for the pane status line. This is the
* case for the most upper panes only.
*/
static int
layout_need_status(struct layout_cell *lc, int at_top)
{
struct layout_cell *first_lc;
if (lc->parent) {
if (lc->parent->type == LAYOUT_LEFTRIGHT)
return (layout_need_status(lc->parent, at_top));
if (at_top)
first_lc = TAILQ_FIRST(&lc->parent->cells);
else
first_lc = TAILQ_LAST(&lc->parent->cells,layout_cells);
if (lc == first_lc)
return (layout_need_status(lc->parent, at_top));
return (0);
}
return (1);
}
/* Update pane offsets and sizes based on their cells. */
void
layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
@@ -170,13 +207,25 @@ layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
struct window_pane *wp;
struct layout_cell *lc;
u_int sx, sy;
int shift, status, at_top;
status = options_get_number(w->options, "pane-border-status");
at_top = (status == 1);
TAILQ_FOREACH(wp, &w->panes, entry) {
if ((lc = wp->layout_cell) == NULL)
continue;
if (status != 0)
shift = layout_need_status(lc, at_top);
else
shift = 0;
wp->xoff = lc->xoff;
wp->yoff = lc->yoff;
if (shift && at_top)
wp->yoff += 1;
/*
* Layout cells are limited by the smallest size of other cells
* within the same row or column; if this isn't the case
@@ -214,6 +263,9 @@ layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
sy = lc->sy;
}
if (shift)
sy -= 1;
window_pane_resize(wp, sx, sy);
}
}
@@ -223,50 +275,55 @@ u_int
layout_count_cells(struct layout_cell *lc)
{
struct layout_cell *lcchild;
u_int n;
u_int count;
switch (lc->type) {
case LAYOUT_WINDOWPANE:
return (1);
case LAYOUT_LEFTRIGHT:
case LAYOUT_TOPBOTTOM:
n = 0;
count = 0;
TAILQ_FOREACH(lcchild, &lc->cells, entry)
n += layout_count_cells(lcchild);
return (n);
count += layout_count_cells(lcchild);
return (count);
default:
fatalx("bad layout type");
}
}
/* Calculate how much size is available to be removed from a cell. */
u_int
layout_resize_check(struct layout_cell *lc, enum layout_type type)
static u_int
layout_resize_check(struct window *w, struct layout_cell *lc,
enum layout_type type)
{
struct layout_cell *lcchild;
u_int available, minimum;
if (lc->type == LAYOUT_WINDOWPANE) {
/* Space available in this cell only. */
minimum = PANE_MINIMUM;
if (type == LAYOUT_LEFTRIGHT)
available = lc->sx;
else
else {
available = lc->sy;
if (available > PANE_MINIMUM)
available -= PANE_MINIMUM;
minimum += layout_need_status(lc,
options_get_number(w->options,
"pane-border-status") == 1);
}
if (available > minimum)
available -= minimum;
else
available = 0;
} else if (lc->type == type) {
/* Same type: total of available space in all child cells. */
available = 0;
TAILQ_FOREACH(lcchild, &lc->cells, entry)
available += layout_resize_check(lcchild, type);
available += layout_resize_check(w, lcchild, type);
} else {
/* Different type: minimum of available space in child cells. */
minimum = UINT_MAX;
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
available = layout_resize_check(lcchild, type);
available = layout_resize_check(w, lcchild, type);
if (available < minimum)
minimum = available;
}
@@ -281,7 +338,8 @@ layout_resize_check(struct layout_cell *lc, enum layout_type type)
* expects the change to have already been bounded to the space available.
*/
void
layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change)
layout_resize_adjust(struct window *w, struct layout_cell *lc,
enum layout_type type, int change)
{
struct layout_cell *lcchild;
@@ -298,7 +356,7 @@ layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change)
/* Child cell runs in a different direction. */
if (lc->type != type) {
TAILQ_FOREACH(lcchild, &lc->cells, entry)
layout_resize_adjust(lcchild, type, change);
layout_resize_adjust(w, lcchild, type, change);
return;
}
@@ -311,12 +369,12 @@ layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change)
if (change == 0)
break;
if (change > 0) {
layout_resize_adjust(lcchild, type, 1);
layout_resize_adjust(w, lcchild, type, 1);
change--;
continue;
}
if (layout_resize_check(lcchild, type) > 0) {
layout_resize_adjust(lcchild, type, -1);
if (layout_resize_check(w, lcchild, type) > 0) {
layout_resize_adjust(w, lcchild, type, -1);
change++;
}
}
@@ -325,7 +383,8 @@ layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change)
/* Destroy a cell and redistribute the space. */
void
layout_destroy_cell(struct layout_cell *lc, struct layout_cell **lcroot)
layout_destroy_cell(struct window *w, struct layout_cell *lc,
struct layout_cell **lcroot)
{
struct layout_cell *lcother, *lcparent;
@@ -346,9 +405,9 @@ layout_destroy_cell(struct layout_cell *lc, struct layout_cell **lcroot)
else
lcother = TAILQ_PREV(lc, layout_cells, entry);
if (lcparent->type == LAYOUT_LEFTRIGHT)
layout_resize_adjust(lcother, lcparent->type, lc->sx + 1);
layout_resize_adjust(w, lcother, lcparent->type, lc->sx + 1);
else
layout_resize_adjust(lcother, lcparent->type, lc->sy + 1);
layout_resize_adjust(w, lcother, lcparent->type, lc->sy + 1);
/* Remove this from the parent's list. */
TAILQ_REMOVE(&lcparent->cells, lc, entry);
@@ -412,7 +471,7 @@ layout_resize(struct window *w, u_int sx, u_int sy)
* window size.
*/
xchange = sx - w->sx;
xlimit = layout_resize_check(lc, LAYOUT_LEFTRIGHT);
xlimit = layout_resize_check(w, lc, LAYOUT_LEFTRIGHT);
if (xchange < 0 && xchange < -xlimit)
xchange = -xlimit;
if (xlimit == 0) {
@@ -422,11 +481,11 @@ layout_resize(struct window *w, u_int sx, u_int sy)
xchange = sx - lc->sx;
}
if (xchange != 0)
layout_resize_adjust(lc, LAYOUT_LEFTRIGHT, xchange);
layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, xchange);
/* Adjust vertically in a similar fashion. */
ychange = sy - w->sy;
ylimit = layout_resize_check(lc, LAYOUT_TOPBOTTOM);
ylimit = layout_resize_check(w, lc, LAYOUT_TOPBOTTOM);
if (ychange < 0 && ychange < -ylimit)
ychange = -ylimit;
if (ylimit == 0) {
@@ -436,7 +495,7 @@ layout_resize(struct window *w, u_int sx, u_int sy)
ychange = sy - lc->sy;
}
if (ychange != 0)
layout_resize_adjust(lc, LAYOUT_TOPBOTTOM, ychange);
layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, ychange);
/* Fix cell offsets. */
layout_fix_offsets(lc);
@@ -480,8 +539,9 @@ layout_resize_pane_to(struct window_pane *wp, enum layout_type type,
void
layout_resize_pane(struct window_pane *wp, enum layout_type type, int change)
{
struct layout_cell *lc, *lcparent;
int needed, size;
struct window *w = wp->window;
struct layout_cell *lc, *lcparent;
int needed, size;
lc = wp->layout_cell;
@@ -502,10 +562,10 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change)
needed = change;
while (needed != 0) {
if (change > 0) {
size = layout_resize_pane_grow(lc, type, needed);
size = layout_resize_pane_grow(w, lc, type, needed);
needed -= size;
} else {
size = layout_resize_pane_shrink(lc, type, needed);
size = layout_resize_pane_shrink(w, lc, type, needed);
needed += size;
}
@@ -520,9 +580,9 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change)
}
/* Helper function to grow pane. */
int
layout_resize_pane_grow(struct layout_cell *lc, enum layout_type type,
int needed)
static int
layout_resize_pane_grow(struct window *w, struct layout_cell *lc,
enum layout_type type, int needed)
{
struct layout_cell *lcadd, *lcremove;
u_int size;
@@ -533,7 +593,7 @@ layout_resize_pane_grow(struct layout_cell *lc, enum layout_type type,
/* Look towards the tail for a suitable cell for reduction. */
lcremove = TAILQ_NEXT(lc, entry);
while (lcremove != NULL) {
size = layout_resize_check(lcremove, type);
size = layout_resize_check(w, lcremove, type);
if (size > 0)
break;
lcremove = TAILQ_NEXT(lcremove, entry);
@@ -543,7 +603,7 @@ layout_resize_pane_grow(struct layout_cell *lc, enum layout_type type,
if (lcremove == NULL) {
lcremove = TAILQ_PREV(lc, layout_cells, entry);
while (lcremove != NULL) {
size = layout_resize_check(lcremove, type);
size = layout_resize_check(w, lcremove, type);
if (size > 0)
break;
lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
@@ -555,15 +615,15 @@ layout_resize_pane_grow(struct layout_cell *lc, enum layout_type type,
/* Change the cells. */
if (size > (u_int) needed)
size = needed;
layout_resize_adjust(lcadd, type, size);
layout_resize_adjust(lcremove, type, -size);
layout_resize_adjust(w, lcadd, type, size);
layout_resize_adjust(w, lcremove, type, -size);
return (size);
}
/* Helper function to shrink pane. */
int
layout_resize_pane_shrink(struct layout_cell *lc, enum layout_type type,
int needed)
static int
layout_resize_pane_shrink(struct window *w, struct layout_cell *lc,
enum layout_type type, int needed)
{
struct layout_cell *lcadd, *lcremove;
u_int size;
@@ -571,7 +631,7 @@ layout_resize_pane_shrink(struct layout_cell *lc, enum layout_type type,
/* Shrinking. Find cell to remove from by walking towards head. */
lcremove = lc;
do {
size = layout_resize_check(lcremove, type);
size = layout_resize_check(w, lcremove, type);
if (size != 0)
break;
lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
@@ -587,8 +647,8 @@ layout_resize_pane_shrink(struct layout_cell *lc, enum layout_type type,
/* Change the cells. */
if (size > (u_int) -needed)
size = -needed;
layout_resize_adjust(lcadd, type, size);
layout_resize_adjust(lcremove, type, -size);
layout_resize_adjust(w, lcadd, type, size);
layout_resize_adjust(w, lcremove, type, -size);
return (size);
}
@@ -600,18 +660,166 @@ layout_assign_pane(struct layout_cell *lc, struct window_pane *wp)
layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
}
/* Calculate the new pane size for resized parent. */
static u_int
layout_new_pane_size(struct window *w, u_int previous, struct layout_cell *lc,
enum layout_type type, u_int size, u_int count_left, u_int size_left)
{
u_int new_size, min, max, available;
/* If this is the last cell, it can take all of the remaining size. */
if (count_left == 1)
return (size_left);
/* How much is available in this parent? */
available = layout_resize_check(w, lc, type);
/*
* Work out the minimum size of this cell and the new size
* proportionate to the previous size.
*/
min = (PANE_MINIMUM + 1) * (count_left - 1);
if (type == LAYOUT_LEFTRIGHT) {
if (lc->sx - available > min)
min = lc->sx - available;
new_size = (lc->sx * size) / previous;
} else {
if (lc->sy - available > min)
min = lc->sy - available;
new_size = (lc->sy * size) / previous;
}
/* Check against the maximum and minimum size. */
max = size_left - min;
if (new_size > max)
new_size = max;
if (new_size < PANE_MINIMUM)
new_size = PANE_MINIMUM;
return (new_size);
}
/* Check if the cell and all its children can be resized to a specific size. */
static int
layout_set_size_check(struct window *w, struct layout_cell *lc,
enum layout_type type, int size)
{
struct layout_cell *lcchild;
u_int new_size, available, previous, count, idx;
/* Cells with no children must just be bigger than minimum. */
if (lc->type == LAYOUT_WINDOWPANE)
return (size >= PANE_MINIMUM);
available = size;
/* Count number of children. */
count = 0;
TAILQ_FOREACH(lcchild, &lc->cells, entry)
count++;
/* Check new size will work for each child. */
if (lc->type == type) {
if (type == LAYOUT_LEFTRIGHT)
previous = lc->sx;
else
previous = lc->sy;
idx = 0;
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
new_size = layout_new_pane_size(w, previous, lcchild,
type, size, count - idx, available);
if (new_size > available)
return (0);
available -= (new_size + 1);
if (!layout_set_size_check(w, lcchild, type, new_size))
return (0);
idx++;
}
} else {
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (lcchild->type == LAYOUT_WINDOWPANE)
continue;
if (!layout_set_size_check(w, lcchild, type, size))
return (0);
}
}
return (1);
}
/* Resize all child cells to fit within the current cell. */
static void
layout_resize_child_cells(struct window *w, struct layout_cell *lc)
{
struct layout_cell *lcchild;
u_int previous, available, count, idx;
if (lc->type == LAYOUT_WINDOWPANE)
return;
/* What is the current size used? */
count = 0;
previous = 0;
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
count++;
if (lc->type == LAYOUT_LEFTRIGHT)
previous += lcchild->sx;
else if (lc->type == LAYOUT_TOPBOTTOM)
previous += lcchild->sy;
}
previous += (count - 1);
/* And how much is available? */
available = 0;
if (lc->type == LAYOUT_LEFTRIGHT)
available = lc->sx;
else if (lc->type == LAYOUT_TOPBOTTOM)
available = lc->sy;
/* Resize children into the new size. */
idx = 0;
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (lc->type == LAYOUT_TOPBOTTOM) {
lcchild->sx = lc->sx;
lcchild->xoff = lc->xoff;
} else {
lcchild->sx = layout_new_pane_size(w, previous, lcchild,
lc->type, lc->sx, count - idx, available);
available -= (lcchild->sx + 1);
}
if (lc->type == LAYOUT_LEFTRIGHT)
lcchild->sy = lc->sy;
else {
lcchild->sy = layout_new_pane_size(w, previous, lcchild,
lc->type, lc->sy, count - idx, available);
available -= (lcchild->sy + 1);
}
layout_resize_child_cells(w, lcchild);
idx++;
}
}
/*
* Split a pane into two. size is a hint, or -1 for default half/half
* split. This must be followed by layout_assign_pane before much else happens!
**/
*/
struct layout_cell *
layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
int insert_before)
int insert_before, int full_size)
{
struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
u_int sx, sy, xoff, yoff, size1, size2;
u_int new_size, saved_size, resize_first = 0;
lc = wp->layout_cell;
/*
* If full_size is specified, add a new cell at the top of the window
* layout. Otherwise, split the cell for the current pane.
*/
if (full_size)
lc = wp->window->layout_root;
else
lc = wp->layout_cell;
/* Copy the old cell size. */
sx = lc->sx;
@@ -633,19 +841,75 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
fatalx("bad layout type");
}
/*
* Calculate new cell sizes. size is the target size or -1 for middle
* split, size1 is the size of the top/left and size2 the bottom/right.
*/
if (type == LAYOUT_LEFTRIGHT)
saved_size = sx;
else
saved_size = sy;
if (size < 0)
size2 = ((saved_size + 1) / 2) - 1;
else if (insert_before)
size2 = saved_size - size - 1;
else
size2 = size;
if (size2 < PANE_MINIMUM)
size2 = PANE_MINIMUM;
else if (size2 > saved_size - 2)
size2 = saved_size - 2;
size1 = saved_size - 1 - size2;
/* Which size are we using? */
if (insert_before)
new_size = size2;
else
new_size = size1;
/* Confirm there is enough space for full size pane. */
if (full_size && !layout_set_size_check(wp->window, lc, type, new_size))
return (NULL);
if (lc->parent != NULL && lc->parent->type == type) {
/*
* If the parent exists and is of the same type as the split,
* create a new cell and insert it after this one.
*/
/* Create the new child cell. */
lcparent = lc->parent;
lcnew = layout_create_cell(lcparent);
if (insert_before)
TAILQ_INSERT_BEFORE(lc, lcnew, entry);
else
TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry);
} else if (full_size && lc->parent == NULL && lc->type == type) {
/*
* If the new full size pane is the same type as the root
* split, insert the new pane under the existing root cell
* instead of creating a new root cell. The existing layout
* must be resized before inserting the new cell.
*/
if (lc->type == LAYOUT_LEFTRIGHT) {
lc->sx = new_size;
layout_resize_child_cells(wp->window, lc);
lc->sx = saved_size;
} else if (lc->type == LAYOUT_TOPBOTTOM) {
lc->sy = new_size;
layout_resize_child_cells(wp->window, lc);
lc->sy = saved_size;
}
resize_first = 1;
/* Create the new cell. */
lcnew = layout_create_cell(lc);
if (lc->type == LAYOUT_LEFTRIGHT)
layout_set_size(lcnew, new_size, sy, 0, 0);
else if (lc->type == LAYOUT_TOPBOTTOM)
layout_set_size(lcnew, sx, new_size, 0, 0);
if (insert_before)
TAILQ_INSERT_HEAD(&lc->cells, lcnew, entry);
else
TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
} else {
/*
* Otherwise create a new parent and insert it.
@@ -679,46 +943,23 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
lc2 = lcnew;
}
/* Set new cell sizes. size is the target size or -1 for middle split,
* size1 is the size of the top/left and size2 the bottom/right.
/*
* Set new cell sizes. size1 is the size of the top/left and size2 the
* bottom/right.
*/
switch (type) {
case LAYOUT_LEFTRIGHT:
if (size < 0)
size2 = ((sx + 1) / 2) - 1;
else if (insert_before)
size2 = sx - size - 1;
else
size2 = size;
if (size2 < PANE_MINIMUM)
size2 = PANE_MINIMUM;
else if (size2 > sx - 2)
size2 = sx - 2;
size1 = sx - 1 - size2;
if (!resize_first && type == LAYOUT_LEFTRIGHT) {
layout_set_size(lc1, size1, sy, xoff, yoff);
layout_set_size(lc2, size2, sy, xoff + lc1->sx + 1, yoff);
break;
case LAYOUT_TOPBOTTOM:
if (size < 0)
size2 = ((sy + 1) / 2) - 1;
else if (insert_before)
size2 = sy - size - 1;
else
size2 = size;
if (size2 < PANE_MINIMUM)
size2 = PANE_MINIMUM;
else if (size2 > sy - 2)
size2 = sy - 2;
size1 = sy - 1 - size2;
} else if (!resize_first && type == LAYOUT_TOPBOTTOM) {
layout_set_size(lc1, sx, size1, xoff, yoff);
layout_set_size(lc2, sx, size2, xoff, yoff + lc1->sy + 1);
break;
default:
fatalx("bad layout type");
}
/* Assign the panes. */
layout_make_leaf(lc, wp);
if (full_size) {
if (!resize_first)
layout_resize_child_cells(wp->window, lc);
layout_fix_offsets(wp->window->layout_root);
} else
layout_make_leaf(lc, wp);
return (lcnew);
}
@@ -727,13 +968,15 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
void
layout_close_pane(struct window_pane *wp)
{
struct window *w = wp->window;
/* Remove the cell. */
layout_destroy_cell(wp->layout_cell, &wp->window->layout_root);
layout_destroy_cell(w, wp->layout_cell, &w->layout_root);
/* Fix pane offsets and sizes. */
if (wp->window->layout_root != NULL) {
layout_fix_offsets(wp->window->layout_root);
layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
if (w->layout_root != NULL) {
layout_fix_offsets(w->layout_root);
layout_fix_panes(w, w->sx, w->sy);
}
notify_window_layout_changed(wp->window);
notify_window_layout_changed(w);
}

View File

@@ -50,6 +50,7 @@ struct mode_key_entry {
*/
int mode;
enum mode_key_cmd cmd;
u_int repeat;
};
/* Edit keys command strings. */
@@ -140,12 +141,14 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
{ MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" },
{ MODEKEYCOPY_MIDDLELINE, "middle-line" },
{ MODEKEYCOPY_NEXTPAGE, "page-down" },
{ MODEKEYCOPY_NEXTPARAGRAPH, "next-paragraph" },
{ MODEKEYCOPY_NEXTSPACE, "next-space" },
{ MODEKEYCOPY_NEXTSPACEEND, "next-space-end" },
{ MODEKEYCOPY_NEXTWORD, "next-word" },
{ MODEKEYCOPY_NEXTWORDEND, "next-word-end" },
{ MODEKEYCOPY_OTHEREND, "other-end" },
{ MODEKEYCOPY_PREVIOUSPAGE, "page-up" },
{ MODEKEYCOPY_PREVIOUSPARAGRAPH, "previous-paragraph" },
{ MODEKEYCOPY_PREVIOUSSPACE, "previous-space" },
{ MODEKEYCOPY_PREVIOUSWORD, "previous-word" },
{ MODEKEYCOPY_RIGHT, "cursor-right" },
@@ -168,337 +171,341 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
/* vi editing keys. */
const struct mode_key_entry mode_key_vi_edit[] = {
{ '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL },
{ '\010' /* C-h */, 0, MODEKEYEDIT_BACKSPACE },
{ '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE },
{ '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE },
{ '\027' /* C-w */, 0, MODEKEYEDIT_DELETEWORD },
{ '\033' /* Escape */, 0, MODEKEYEDIT_SWITCHMODE },
{ '\n', 0, MODEKEYEDIT_ENTER },
{ '\r', 0, MODEKEYEDIT_ENTER },
{ KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE },
{ KEYC_DC, 0, MODEKEYEDIT_DELETE },
{ KEYC_DOWN, 0, MODEKEYEDIT_HISTORYDOWN },
{ KEYC_LEFT, 0, MODEKEYEDIT_CURSORLEFT },
{ KEYC_RIGHT, 0, MODEKEYEDIT_CURSORRIGHT },
{ KEYC_UP, 0, MODEKEYEDIT_HISTORYUP },
{ KEYC_HOME, 0, MODEKEYEDIT_STARTOFLINE },
{ KEYC_END, 0, MODEKEYEDIT_ENDOFLINE },
{ '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL, 1 },
{ '\010' /* C-h */, 0, MODEKEYEDIT_BACKSPACE, 1 },
{ '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE, 1 },
{ '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE, 1 },
{ '\027' /* C-w */, 0, MODEKEYEDIT_DELETEWORD, 1 },
{ '\033' /* Escape */, 0, MODEKEYEDIT_SWITCHMODE, 1 },
{ '\n', 0, MODEKEYEDIT_ENTER, 1 },
{ '\r', 0, MODEKEYEDIT_ENTER, 1 },
{ KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE, 1 },
{ KEYC_DC, 0, MODEKEYEDIT_DELETE, 1 },
{ KEYC_DOWN, 0, MODEKEYEDIT_HISTORYDOWN, 1 },
{ KEYC_LEFT, 0, MODEKEYEDIT_CURSORLEFT, 1 },
{ KEYC_RIGHT, 0, MODEKEYEDIT_CURSORRIGHT, 1 },
{ KEYC_UP, 0, MODEKEYEDIT_HISTORYUP, 1 },
{ KEYC_HOME, 0, MODEKEYEDIT_STARTOFLINE, 1 },
{ KEYC_END, 0, MODEKEYEDIT_ENDOFLINE, 1 },
{ '$', 1, MODEKEYEDIT_ENDOFLINE },
{ '0', 1, MODEKEYEDIT_STARTOFLINE },
{ 'A', 1, MODEKEYEDIT_SWITCHMODEAPPENDLINE },
{ 'B', 1, MODEKEYEDIT_PREVIOUSSPACE },
{ 'C', 1, MODEKEYEDIT_SWITCHMODECHANGELINE },
{ 'D', 1, MODEKEYEDIT_DELETETOENDOFLINE },
{ 'E', 1, MODEKEYEDIT_NEXTSPACEEND },
{ 'I', 1, MODEKEYEDIT_SWITCHMODEBEGINLINE },
{ 'S', 1, MODEKEYEDIT_SWITCHMODESUBSTITUTELINE },
{ 'W', 1, MODEKEYEDIT_NEXTSPACE },
{ 'X', 1, MODEKEYEDIT_BACKSPACE },
{ '\003' /* C-c */, 1, MODEKEYEDIT_CANCEL },
{ '\010' /* C-h */, 1, MODEKEYEDIT_BACKSPACE },
{ '\n', 1, MODEKEYEDIT_ENTER },
{ '\r', 1, MODEKEYEDIT_ENTER },
{ '^', 1, MODEKEYEDIT_STARTOFLINE },
{ 'a', 1, MODEKEYEDIT_SWITCHMODEAPPEND },
{ 'b', 1, MODEKEYEDIT_PREVIOUSWORD },
{ 'd', 1, MODEKEYEDIT_DELETELINE },
{ 'e', 1, MODEKEYEDIT_NEXTWORDEND },
{ 'h', 1, MODEKEYEDIT_CURSORLEFT },
{ 'i', 1, MODEKEYEDIT_SWITCHMODE },
{ 'j', 1, MODEKEYEDIT_HISTORYDOWN },
{ 'k', 1, MODEKEYEDIT_HISTORYUP },
{ 'l', 1, MODEKEYEDIT_CURSORRIGHT },
{ 'p', 1, MODEKEYEDIT_PASTE },
{ 's', 1, MODEKEYEDIT_SWITCHMODESUBSTITUTE },
{ 'w', 1, MODEKEYEDIT_NEXTWORD },
{ 'x', 1, MODEKEYEDIT_DELETE },
{ KEYC_BSPACE, 1, MODEKEYEDIT_BACKSPACE },
{ KEYC_DC, 1, MODEKEYEDIT_DELETE },
{ KEYC_DOWN, 1, MODEKEYEDIT_HISTORYDOWN },
{ KEYC_LEFT, 1, MODEKEYEDIT_CURSORLEFT },
{ KEYC_RIGHT, 1, MODEKEYEDIT_CURSORRIGHT },
{ KEYC_UP, 1, MODEKEYEDIT_HISTORYUP },
{ '$', 1, MODEKEYEDIT_ENDOFLINE, 1 },
{ '0', 1, MODEKEYEDIT_STARTOFLINE, 1 },
{ 'A', 1, MODEKEYEDIT_SWITCHMODEAPPENDLINE, 1 },
{ 'B', 1, MODEKEYEDIT_PREVIOUSSPACE, 1 },
{ 'C', 1, MODEKEYEDIT_SWITCHMODECHANGELINE, 1 },
{ 'D', 1, MODEKEYEDIT_DELETETOENDOFLINE, 1 },
{ 'E', 1, MODEKEYEDIT_NEXTSPACEEND, 1 },
{ 'I', 1, MODEKEYEDIT_SWITCHMODEBEGINLINE, 1 },
{ 'S', 1, MODEKEYEDIT_SWITCHMODESUBSTITUTELINE, 1 },
{ 'W', 1, MODEKEYEDIT_NEXTSPACE, 1 },
{ 'X', 1, MODEKEYEDIT_BACKSPACE, 1 },
{ '\003' /* C-c */, 1, MODEKEYEDIT_CANCEL, 1 },
{ '\010' /* C-h */, 1, MODEKEYEDIT_BACKSPACE, 1 },
{ '\n', 1, MODEKEYEDIT_ENTER, 1 },
{ '\r', 1, MODEKEYEDIT_ENTER, 1 },
{ '^', 1, MODEKEYEDIT_STARTOFLINE, 1 },
{ 'a', 1, MODEKEYEDIT_SWITCHMODEAPPEND, 1 },
{ 'b', 1, MODEKEYEDIT_PREVIOUSWORD, 1 },
{ 'd', 1, MODEKEYEDIT_DELETELINE, 1 },
{ 'e', 1, MODEKEYEDIT_NEXTWORDEND, 1 },
{ 'h', 1, MODEKEYEDIT_CURSORLEFT, 1 },
{ 'i', 1, MODEKEYEDIT_SWITCHMODE, 1 },
{ 'j', 1, MODEKEYEDIT_HISTORYDOWN, 1 },
{ 'k', 1, MODEKEYEDIT_HISTORYUP, 1 },
{ 'l', 1, MODEKEYEDIT_CURSORRIGHT, 1 },
{ 'p', 1, MODEKEYEDIT_PASTE, 1 },
{ 's', 1, MODEKEYEDIT_SWITCHMODESUBSTITUTE, 1 },
{ 'w', 1, MODEKEYEDIT_NEXTWORD, 1 },
{ 'x', 1, MODEKEYEDIT_DELETE, 1 },
{ KEYC_BSPACE, 1, MODEKEYEDIT_BACKSPACE, 1 },
{ KEYC_DC, 1, MODEKEYEDIT_DELETE, 1 },
{ KEYC_DOWN, 1, MODEKEYEDIT_HISTORYDOWN, 1 },
{ KEYC_LEFT, 1, MODEKEYEDIT_CURSORLEFT, 1 },
{ KEYC_RIGHT, 1, MODEKEYEDIT_CURSORRIGHT, 1 },
{ KEYC_UP, 1, MODEKEYEDIT_HISTORYUP, 1 },
{ 0, -1, 0 }
{ 0, -1, 0, 1 }
};
struct mode_key_tree mode_key_tree_vi_edit;
/* vi choice selection keys. */
const struct mode_key_entry mode_key_vi_choice[] = {
{ '0' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '1' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '2' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '3' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '4' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '5' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '6' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '7' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '8' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '9' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '\002' /* C-b */, 0, MODEKEYCHOICE_PAGEUP },
{ '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL },
{ '\005' /* C-e */, 0, MODEKEYCHOICE_SCROLLDOWN },
{ '\006' /* C-f */, 0, MODEKEYCHOICE_PAGEDOWN },
{ '\031' /* C-y */, 0, MODEKEYCHOICE_SCROLLUP },
{ '\n', 0, MODEKEYCHOICE_CHOOSE },
{ '\r', 0, MODEKEYCHOICE_CHOOSE },
{ 'j', 0, MODEKEYCHOICE_DOWN },
{ 'k', 0, MODEKEYCHOICE_UP },
{ 'q', 0, MODEKEYCHOICE_CANCEL },
{ KEYC_HOME, 0, MODEKEYCHOICE_STARTOFLIST },
{ 'g', 0, MODEKEYCHOICE_STARTOFLIST },
{ 'H', 0, MODEKEYCHOICE_TOPLINE },
{ 'L', 0, MODEKEYCHOICE_BOTTOMLINE },
{ 'G', 0, MODEKEYCHOICE_ENDOFLIST },
{ KEYC_END, 0, MODEKEYCHOICE_ENDOFLIST },
{ KEYC_BSPACE, 0, MODEKEYCHOICE_BACKSPACE },
{ KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLDOWN },
{ KEYC_DOWN, 0, MODEKEYCHOICE_DOWN },
{ KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN },
{ KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP },
{ KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP },
{ KEYC_UP, 0, MODEKEYCHOICE_UP },
{ ' ', 0, MODEKEYCHOICE_TREE_TOGGLE },
{ KEYC_LEFT, 0, MODEKEYCHOICE_TREE_COLLAPSE },
{ KEYC_RIGHT, 0, MODEKEYCHOICE_TREE_EXPAND },
{ KEYC_LEFT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_COLLAPSE_ALL },
{ KEYC_RIGHT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_EXPAND_ALL },
{ KEYC_MOUSEDOWN1_PANE, 0, MODEKEYCHOICE_CHOOSE },
{ KEYC_MOUSEDOWN3_PANE, 0, MODEKEYCHOICE_TREE_TOGGLE },
{ KEYC_WHEELUP_PANE, 0, MODEKEYCHOICE_UP },
{ KEYC_WHEELDOWN_PANE, 0, MODEKEYCHOICE_DOWN },
{ '0' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '1' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '2' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '3' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '4' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '5' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '6' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '7' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '8' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '9' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '\002' /* C-b */, 0, MODEKEYCHOICE_PAGEUP, 1 },
{ '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL, 1 },
{ '\005' /* C-e */, 0, MODEKEYCHOICE_SCROLLDOWN, 1 },
{ '\006' /* C-f */, 0, MODEKEYCHOICE_PAGEDOWN, 1 },
{ '\031' /* C-y */, 0, MODEKEYCHOICE_SCROLLUP, 1 },
{ '\n', 0, MODEKEYCHOICE_CHOOSE, 1 },
{ '\r', 0, MODEKEYCHOICE_CHOOSE, 1 },
{ 'j', 0, MODEKEYCHOICE_DOWN, 1 },
{ 'k', 0, MODEKEYCHOICE_UP, 1 },
{ 'q', 0, MODEKEYCHOICE_CANCEL, 1 },
{ KEYC_HOME, 0, MODEKEYCHOICE_STARTOFLIST, 1 },
{ 'g', 0, MODEKEYCHOICE_STARTOFLIST, 1 },
{ 'H', 0, MODEKEYCHOICE_TOPLINE, 1 },
{ 'L', 0, MODEKEYCHOICE_BOTTOMLINE, 1 },
{ 'G', 0, MODEKEYCHOICE_ENDOFLIST, 1 },
{ KEYC_END, 0, MODEKEYCHOICE_ENDOFLIST, 1 },
{ KEYC_BSPACE, 0, MODEKEYCHOICE_BACKSPACE, 1 },
{ KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLDOWN, 1 },
{ KEYC_DOWN, 0, MODEKEYCHOICE_DOWN, 1 },
{ KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN, 1 },
{ KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP, 1 },
{ KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP, 1 },
{ KEYC_UP, 0, MODEKEYCHOICE_UP, 1 },
{ ' ', 0, MODEKEYCHOICE_TREE_TOGGLE, 1 },
{ KEYC_LEFT, 0, MODEKEYCHOICE_TREE_COLLAPSE, 1 },
{ KEYC_RIGHT, 0, MODEKEYCHOICE_TREE_EXPAND, 1 },
{ KEYC_LEFT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_COLLAPSE_ALL, 1 },
{ KEYC_RIGHT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_EXPAND_ALL, 1 },
{ KEYC_MOUSEDOWN1_PANE, 0, MODEKEYCHOICE_CHOOSE, 1 },
{ KEYC_MOUSEDOWN3_PANE, 0, MODEKEYCHOICE_TREE_TOGGLE, 1 },
{ KEYC_WHEELUP_PANE, 0, MODEKEYCHOICE_UP, 1 },
{ KEYC_WHEELDOWN_PANE, 0, MODEKEYCHOICE_DOWN, 1 },
{ 0, -1, 0 }
{ 0, -1, 0, 1 }
};
struct mode_key_tree mode_key_tree_vi_choice;
/* vi copy mode keys. */
const struct mode_key_entry mode_key_vi_copy[] = {
{ ' ', 0, MODEKEYCOPY_STARTSELECTION },
{ '"', 0, MODEKEYCOPY_STARTNAMEDBUFFER },
{ '$', 0, MODEKEYCOPY_ENDOFLINE },
{ ',', 0, MODEKEYCOPY_JUMPREVERSE },
{ ';', 0, MODEKEYCOPY_JUMPAGAIN },
{ '/', 0, MODEKEYCOPY_SEARCHDOWN },
{ '0', 0, MODEKEYCOPY_STARTOFLINE },
{ '1', 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '2', 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '3', 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '4', 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '5', 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '6', 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '7', 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '8', 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '9', 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ ':', 0, MODEKEYCOPY_GOTOLINE },
{ '?', 0, MODEKEYCOPY_SEARCHUP },
{ 'A', 0, MODEKEYCOPY_APPENDSELECTION },
{ 'B', 0, MODEKEYCOPY_PREVIOUSSPACE },
{ 'D', 0, MODEKEYCOPY_COPYENDOFLINE },
{ 'E', 0, MODEKEYCOPY_NEXTSPACEEND },
{ 'F', 0, MODEKEYCOPY_JUMPBACK },
{ 'G', 0, MODEKEYCOPY_HISTORYBOTTOM },
{ 'H', 0, MODEKEYCOPY_TOPLINE },
{ 'J', 0, MODEKEYCOPY_SCROLLDOWN },
{ 'K', 0, MODEKEYCOPY_SCROLLUP },
{ 'L', 0, MODEKEYCOPY_BOTTOMLINE },
{ 'M', 0, MODEKEYCOPY_MIDDLELINE },
{ 'N', 0, MODEKEYCOPY_SEARCHREVERSE },
{ 'T', 0, MODEKEYCOPY_JUMPTOBACK },
{ 'V', 0, MODEKEYCOPY_SELECTLINE },
{ 'W', 0, MODEKEYCOPY_NEXTSPACE },
{ '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE },
{ '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL },
{ '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN },
{ '\005' /* C-e */, 0, MODEKEYCOPY_SCROLLDOWN },
{ '\006' /* C-f */, 0, MODEKEYCOPY_NEXTPAGE },
{ '\010' /* C-h */, 0, MODEKEYCOPY_LEFT },
{ '\025' /* C-u */, 0, MODEKEYCOPY_HALFPAGEUP },
{ '\031' /* C-y */, 0, MODEKEYCOPY_SCROLLUP },
{ '\033' /* Escape */, 0, MODEKEYCOPY_CLEARSELECTION },
{ '\n', 0, MODEKEYCOPY_COPYSELECTION },
{ '\r', 0, MODEKEYCOPY_COPYSELECTION },
{ '^', 0, MODEKEYCOPY_BACKTOINDENTATION },
{ 'b', 0, MODEKEYCOPY_PREVIOUSWORD },
{ 'e', 0, MODEKEYCOPY_NEXTWORDEND },
{ 'f', 0, MODEKEYCOPY_JUMP },
{ 'g', 0, MODEKEYCOPY_HISTORYTOP },
{ 'h', 0, MODEKEYCOPY_LEFT },
{ 'j', 0, MODEKEYCOPY_DOWN },
{ 'k', 0, MODEKEYCOPY_UP },
{ 'l', 0, MODEKEYCOPY_RIGHT },
{ 'n', 0, MODEKEYCOPY_SEARCHAGAIN },
{ 'o', 0, MODEKEYCOPY_OTHEREND },
{ 't', 0, MODEKEYCOPY_JUMPTO },
{ 'q', 0, MODEKEYCOPY_CANCEL },
{ 'v', 0, MODEKEYCOPY_RECTANGLETOGGLE },
{ 'w', 0, MODEKEYCOPY_NEXTWORD },
{ KEYC_BSPACE, 0, MODEKEYCOPY_LEFT },
{ KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLDOWN },
{ KEYC_DOWN, 0, MODEKEYCOPY_DOWN },
{ KEYC_LEFT, 0, MODEKEYCOPY_LEFT },
{ KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE },
{ KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE },
{ KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT },
{ KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP },
{ KEYC_UP, 0, MODEKEYCOPY_UP },
{ KEYC_WHEELUP_PANE, 0, MODEKEYCOPY_SCROLLUP },
{ KEYC_WHEELDOWN_PANE, 0, MODEKEYCOPY_SCROLLDOWN },
{ KEYC_MOUSEDRAG1_PANE, 0, MODEKEYCOPY_STARTSELECTION },
{ KEYC_MOUSEDRAGEND1_PANE, 0, MODEKEYCOPY_COPYSELECTION },
{ ' ', 0, MODEKEYCOPY_STARTSELECTION, 1 },
{ '"', 0, MODEKEYCOPY_STARTNAMEDBUFFER, 1 },
{ '$', 0, MODEKEYCOPY_ENDOFLINE, 1 },
{ ',', 0, MODEKEYCOPY_JUMPREVERSE, 1 },
{ ';', 0, MODEKEYCOPY_JUMPAGAIN, 1 },
{ '/', 0, MODEKEYCOPY_SEARCHDOWN, 1 },
{ '0', 0, MODEKEYCOPY_STARTOFLINE, 1 },
{ '1', 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '2', 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '3', 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '4', 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '5', 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '6', 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '7', 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '8', 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '9', 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ ':', 0, MODEKEYCOPY_GOTOLINE, 1 },
{ '?', 0, MODEKEYCOPY_SEARCHUP, 1 },
{ 'A', 0, MODEKEYCOPY_APPENDSELECTION, 1 },
{ 'B', 0, MODEKEYCOPY_PREVIOUSSPACE, 1 },
{ 'D', 0, MODEKEYCOPY_COPYENDOFLINE, 1 },
{ 'E', 0, MODEKEYCOPY_NEXTSPACEEND, 1 },
{ 'F', 0, MODEKEYCOPY_JUMPBACK, 1 },
{ 'G', 0, MODEKEYCOPY_HISTORYBOTTOM, 1 },
{ 'H', 0, MODEKEYCOPY_TOPLINE, 1 },
{ 'J', 0, MODEKEYCOPY_SCROLLDOWN, 1 },
{ 'K', 0, MODEKEYCOPY_SCROLLUP, 1 },
{ 'L', 0, MODEKEYCOPY_BOTTOMLINE, 1 },
{ 'M', 0, MODEKEYCOPY_MIDDLELINE, 1 },
{ 'N', 0, MODEKEYCOPY_SEARCHREVERSE, 1 },
{ 'T', 0, MODEKEYCOPY_JUMPTOBACK, 1 },
{ 'V', 0, MODEKEYCOPY_SELECTLINE, 1 },
{ 'W', 0, MODEKEYCOPY_NEXTSPACE, 1 },
{ '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE, 1 },
{ '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL, 1 },
{ '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN, 1 },
{ '\005' /* C-e */, 0, MODEKEYCOPY_SCROLLDOWN, 1 },
{ '\006' /* C-f */, 0, MODEKEYCOPY_NEXTPAGE, 1 },
{ '\010' /* C-h */, 0, MODEKEYCOPY_LEFT, 1 },
{ '\025' /* C-u */, 0, MODEKEYCOPY_HALFPAGEUP, 1 },
{ '\031' /* C-y */, 0, MODEKEYCOPY_SCROLLUP, 1 },
{ '\033' /* Escape */, 0, MODEKEYCOPY_CLEARSELECTION, 1 },
{ '\n', 0, MODEKEYCOPY_COPYSELECTION, 1 },
{ '\r', 0, MODEKEYCOPY_COPYSELECTION, 1 },
{ '^', 0, MODEKEYCOPY_BACKTOINDENTATION, 1 },
{ 'b', 0, MODEKEYCOPY_PREVIOUSWORD, 1 },
{ 'e', 0, MODEKEYCOPY_NEXTWORDEND, 1 },
{ 'f', 0, MODEKEYCOPY_JUMP, 1 },
{ 'g', 0, MODEKEYCOPY_HISTORYTOP, 1 },
{ 'h', 0, MODEKEYCOPY_LEFT, 1 },
{ 'j', 0, MODEKEYCOPY_DOWN, 1 },
{ 'k', 0, MODEKEYCOPY_UP, 1 },
{ 'l', 0, MODEKEYCOPY_RIGHT, 1 },
{ 'n', 0, MODEKEYCOPY_SEARCHAGAIN, 1 },
{ 'o', 0, MODEKEYCOPY_OTHEREND, 1 },
{ 't', 0, MODEKEYCOPY_JUMPTO, 1 },
{ 'q', 0, MODEKEYCOPY_CANCEL, 1 },
{ 'v', 0, MODEKEYCOPY_RECTANGLETOGGLE, 1 },
{ 'w', 0, MODEKEYCOPY_NEXTWORD, 1 },
{ '{', 0, MODEKEYCOPY_PREVIOUSPARAGRAPH, 1 },
{ '}', 0, MODEKEYCOPY_NEXTPARAGRAPH, 1 },
{ KEYC_BSPACE, 0, MODEKEYCOPY_LEFT, 1 },
{ KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLDOWN, 1 },
{ KEYC_DOWN, 0, MODEKEYCOPY_DOWN, 1 },
{ KEYC_LEFT, 0, MODEKEYCOPY_LEFT, 1 },
{ KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE, 1 },
{ KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE, 1 },
{ KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT, 1 },
{ KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP, 1 },
{ KEYC_UP, 0, MODEKEYCOPY_UP, 1 },
{ KEYC_WHEELUP_PANE, 0, MODEKEYCOPY_SCROLLUP, 1 },
{ KEYC_WHEELDOWN_PANE, 0, MODEKEYCOPY_SCROLLDOWN, 1 },
{ KEYC_MOUSEDRAG1_PANE, 0, MODEKEYCOPY_STARTSELECTION, 1 },
{ KEYC_MOUSEDRAGEND1_PANE, 0, MODEKEYCOPY_COPYSELECTION, 1 },
{ 0, -1, 0 }
{ 0, -1, 0, 1 }
};
struct mode_key_tree mode_key_tree_vi_copy;
/* emacs editing keys. */
const struct mode_key_entry mode_key_emacs_edit[] = {
{ '\001' /* C-a */, 0, MODEKEYEDIT_STARTOFLINE },
{ '\002' /* C-b */, 0, MODEKEYEDIT_CURSORLEFT },
{ '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL },
{ '\004' /* C-d */, 0, MODEKEYEDIT_DELETE },
{ '\005' /* C-e */, 0, MODEKEYEDIT_ENDOFLINE },
{ '\006' /* C-f */, 0, MODEKEYEDIT_CURSORRIGHT },
{ '\010' /* C-H */, 0, MODEKEYEDIT_BACKSPACE },
{ '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE },
{ '\013' /* C-k */, 0, MODEKEYEDIT_DELETETOENDOFLINE },
{ '\016' /* C-n */, 0, MODEKEYEDIT_HISTORYDOWN },
{ '\020' /* C-p */, 0, MODEKEYEDIT_HISTORYUP },
{ '\024' /* C-t */, 0, MODEKEYEDIT_TRANSPOSECHARS },
{ '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE },
{ '\027' /* C-w */, 0, MODEKEYEDIT_DELETEWORD },
{ '\031' /* C-y */, 0, MODEKEYEDIT_PASTE },
{ '\033' /* Escape */, 0, MODEKEYEDIT_CANCEL },
{ '\n', 0, MODEKEYEDIT_ENTER },
{ '\r', 0, MODEKEYEDIT_ENTER },
{ 'b' | KEYC_ESCAPE, 0, MODEKEYEDIT_PREVIOUSWORD },
{ 'f' | KEYC_ESCAPE, 0, MODEKEYEDIT_NEXTWORDEND },
{ 'm' | KEYC_ESCAPE, 0, MODEKEYEDIT_STARTOFLINE },
{ KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE },
{ KEYC_DC, 0, MODEKEYEDIT_DELETE },
{ KEYC_DOWN, 0, MODEKEYEDIT_HISTORYDOWN },
{ KEYC_LEFT, 0, MODEKEYEDIT_CURSORLEFT },
{ KEYC_RIGHT, 0, MODEKEYEDIT_CURSORRIGHT },
{ KEYC_UP, 0, MODEKEYEDIT_HISTORYUP },
{ KEYC_HOME, 0, MODEKEYEDIT_STARTOFLINE },
{ KEYC_END, 0, MODEKEYEDIT_ENDOFLINE },
{ '\001' /* C-a */, 0, MODEKEYEDIT_STARTOFLINE, 1 },
{ '\002' /* C-b */, 0, MODEKEYEDIT_CURSORLEFT, 1 },
{ '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL, 1 },
{ '\004' /* C-d */, 0, MODEKEYEDIT_DELETE, 1 },
{ '\005' /* C-e */, 0, MODEKEYEDIT_ENDOFLINE, 1 },
{ '\006' /* C-f */, 0, MODEKEYEDIT_CURSORRIGHT, 1 },
{ '\010' /* C-H */, 0, MODEKEYEDIT_BACKSPACE, 1 },
{ '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE, 1 },
{ '\013' /* C-k */, 0, MODEKEYEDIT_DELETETOENDOFLINE, 1 },
{ '\016' /* C-n */, 0, MODEKEYEDIT_HISTORYDOWN, 1 },
{ '\020' /* C-p */, 0, MODEKEYEDIT_HISTORYUP, 1 },
{ '\024' /* C-t */, 0, MODEKEYEDIT_TRANSPOSECHARS, 1 },
{ '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE, 1 },
{ '\027' /* C-w */, 0, MODEKEYEDIT_DELETEWORD, 1 },
{ '\031' /* C-y */, 0, MODEKEYEDIT_PASTE, 1 },
{ '\033' /* Escape */, 0, MODEKEYEDIT_CANCEL, 1 },
{ '\n', 0, MODEKEYEDIT_ENTER, 1 },
{ '\r', 0, MODEKEYEDIT_ENTER, 1 },
{ 'b' | KEYC_ESCAPE, 0, MODEKEYEDIT_PREVIOUSWORD, 1 },
{ 'f' | KEYC_ESCAPE, 0, MODEKEYEDIT_NEXTWORDEND, 1 },
{ 'm' | KEYC_ESCAPE, 0, MODEKEYEDIT_STARTOFLINE, 1 },
{ KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE, 1 },
{ KEYC_DC, 0, MODEKEYEDIT_DELETE, 1 },
{ KEYC_DOWN, 0, MODEKEYEDIT_HISTORYDOWN, 1 },
{ KEYC_LEFT, 0, MODEKEYEDIT_CURSORLEFT, 1 },
{ KEYC_RIGHT, 0, MODEKEYEDIT_CURSORRIGHT, 1 },
{ KEYC_UP, 0, MODEKEYEDIT_HISTORYUP, 1 },
{ KEYC_HOME, 0, MODEKEYEDIT_STARTOFLINE, 1 },
{ KEYC_END, 0, MODEKEYEDIT_ENDOFLINE, 1 },
{ 0, -1, 0 }
{ 0, -1, 0, 1 }
};
struct mode_key_tree mode_key_tree_emacs_edit;
/* emacs choice selection keys. */
const struct mode_key_entry mode_key_emacs_choice[] = {
{ '0' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '1' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '2' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '3' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '4' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '5' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '6' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '7' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '8' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '9' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX },
{ '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL },
{ '\016' /* C-n */, 0, MODEKEYCHOICE_DOWN },
{ '\020' /* C-p */, 0, MODEKEYCHOICE_UP },
{ '\026' /* C-v */, 0, MODEKEYCHOICE_PAGEDOWN },
{ '\033' /* Escape */, 0, MODEKEYCHOICE_CANCEL },
{ '\n', 0, MODEKEYCHOICE_CHOOSE },
{ '\r', 0, MODEKEYCHOICE_CHOOSE },
{ 'q', 0, MODEKEYCHOICE_CANCEL },
{ 'v' | KEYC_ESCAPE, 0, MODEKEYCHOICE_PAGEUP },
{ KEYC_HOME, 0, MODEKEYCHOICE_STARTOFLIST },
{ '<' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTOFLIST },
{ 'R' | KEYC_ESCAPE, 0, MODEKEYCHOICE_TOPLINE },
{ '>' | KEYC_ESCAPE, 0, MODEKEYCHOICE_ENDOFLIST },
{ KEYC_END, 0, MODEKEYCHOICE_ENDOFLIST },
{ KEYC_BSPACE, 0, MODEKEYCHOICE_BACKSPACE },
{ KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLDOWN },
{ KEYC_DOWN, 0, MODEKEYCHOICE_DOWN },
{ KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN },
{ KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP },
{ KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP },
{ KEYC_UP, 0, MODEKEYCHOICE_UP },
{ ' ', 0, MODEKEYCHOICE_TREE_TOGGLE },
{ KEYC_LEFT, 0, MODEKEYCHOICE_TREE_COLLAPSE },
{ KEYC_RIGHT, 0, MODEKEYCHOICE_TREE_EXPAND },
{ KEYC_LEFT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_COLLAPSE_ALL },
{ KEYC_RIGHT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_EXPAND_ALL },
{ KEYC_MOUSEDOWN1_PANE, 0, MODEKEYCHOICE_CHOOSE },
{ KEYC_MOUSEDOWN3_PANE, 0, MODEKEYCHOICE_TREE_TOGGLE },
{ KEYC_WHEELUP_PANE, 0, MODEKEYCHOICE_UP },
{ KEYC_WHEELDOWN_PANE, 0, MODEKEYCHOICE_DOWN },
{ '0' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '1' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '2' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '3' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '4' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '5' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '6' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '7' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '8' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '9' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTNUMBERPREFIX, 1 },
{ '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL, 1 },
{ '\016' /* C-n */, 0, MODEKEYCHOICE_DOWN, 1 },
{ '\020' /* C-p */, 0, MODEKEYCHOICE_UP, 1 },
{ '\026' /* C-v */, 0, MODEKEYCHOICE_PAGEDOWN, 1 },
{ '\033' /* Escape */, 0, MODEKEYCHOICE_CANCEL, 1 },
{ '\n', 0, MODEKEYCHOICE_CHOOSE, 1 },
{ '\r', 0, MODEKEYCHOICE_CHOOSE, 1 },
{ 'q', 0, MODEKEYCHOICE_CANCEL, 1 },
{ 'v' | KEYC_ESCAPE, 0, MODEKEYCHOICE_PAGEUP, 1 },
{ KEYC_HOME, 0, MODEKEYCHOICE_STARTOFLIST, 1 },
{ '<' | KEYC_ESCAPE, 0, MODEKEYCHOICE_STARTOFLIST, 1 },
{ 'R' | KEYC_ESCAPE, 0, MODEKEYCHOICE_TOPLINE, 1 },
{ '>' | KEYC_ESCAPE, 0, MODEKEYCHOICE_ENDOFLIST, 1 },
{ KEYC_END, 0, MODEKEYCHOICE_ENDOFLIST, 1 },
{ KEYC_BSPACE, 0, MODEKEYCHOICE_BACKSPACE, 1 },
{ KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLDOWN, 1 },
{ KEYC_DOWN, 0, MODEKEYCHOICE_DOWN, 1 },
{ KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN, 1 },
{ KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP, 1 },
{ KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP, 1 },
{ KEYC_UP, 0, MODEKEYCHOICE_UP, 1 },
{ ' ', 0, MODEKEYCHOICE_TREE_TOGGLE, 1 },
{ KEYC_LEFT, 0, MODEKEYCHOICE_TREE_COLLAPSE, 1 },
{ KEYC_RIGHT, 0, MODEKEYCHOICE_TREE_EXPAND, 1 },
{ KEYC_LEFT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_COLLAPSE_ALL, 1 },
{ KEYC_RIGHT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_EXPAND_ALL, 1 },
{ KEYC_MOUSEDOWN1_PANE, 0, MODEKEYCHOICE_CHOOSE, 1 },
{ KEYC_MOUSEDOWN3_PANE, 0, MODEKEYCHOICE_TREE_TOGGLE, 1 },
{ KEYC_WHEELUP_PANE, 0, MODEKEYCHOICE_UP, 5 },
{ KEYC_WHEELDOWN_PANE, 0, MODEKEYCHOICE_DOWN, 5 },
{ 0, -1, 0 }
{ 0, -1, 0, 1 }
};
struct mode_key_tree mode_key_tree_emacs_choice;
/* emacs copy mode keys. */
const struct mode_key_entry mode_key_emacs_copy[] = {
{ ' ', 0, MODEKEYCOPY_NEXTPAGE },
{ ',', 0, MODEKEYCOPY_JUMPREVERSE },
{ ';', 0, MODEKEYCOPY_JUMPAGAIN },
{ '1' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '2' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '3' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '4' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '5' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '6' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '7' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '8' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '9' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '<' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYTOP },
{ '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM },
{ 'F', 0, MODEKEYCOPY_JUMPBACK },
{ 'N', 0, MODEKEYCOPY_SEARCHREVERSE },
{ 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE },
{ 'R', 0, MODEKEYCOPY_RECTANGLETOGGLE },
{ 'T', 0, MODEKEYCOPY_JUMPTOBACK },
{ '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION },
{ '\001' /* C-a */, 0, MODEKEYCOPY_STARTOFLINE },
{ '\002' /* C-b */, 0, MODEKEYCOPY_LEFT },
{ '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL },
{ '\005' /* C-e */, 0, MODEKEYCOPY_ENDOFLINE },
{ '\006' /* C-f */, 0, MODEKEYCOPY_RIGHT },
{ '\007' /* C-g */, 0, MODEKEYCOPY_CLEARSELECTION },
{ '\013' /* C-k */, 0, MODEKEYCOPY_COPYENDOFLINE },
{ '\016' /* C-n */, 0, MODEKEYCOPY_DOWN },
{ '\020' /* C-p */, 0, MODEKEYCOPY_UP },
{ '\022' /* C-r */, 0, MODEKEYCOPY_SEARCHUP },
{ '\023' /* C-s */, 0, MODEKEYCOPY_SEARCHDOWN },
{ '\026' /* C-v */, 0, MODEKEYCOPY_NEXTPAGE },
{ '\027' /* C-w */, 0, MODEKEYCOPY_COPYSELECTION },
{ '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL },
{ 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD },
{ 'f', 0, MODEKEYCOPY_JUMP },
{ 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORDEND },
{ 'g', 0, MODEKEYCOPY_GOTOLINE },
{ 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION },
{ 'n', 0, MODEKEYCOPY_SEARCHAGAIN },
{ 'q', 0, MODEKEYCOPY_CANCEL },
{ 'r' | KEYC_ESCAPE, 0, MODEKEYCOPY_MIDDLELINE },
{ 't', 0, MODEKEYCOPY_JUMPTO },
{ 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE },
{ 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION },
{ KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLDOWN },
{ KEYC_DOWN | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEDOWN },
{ KEYC_DOWN, 0, MODEKEYCOPY_DOWN },
{ KEYC_LEFT, 0, MODEKEYCOPY_LEFT },
{ KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE },
{ KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE },
{ KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT },
{ KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP },
{ KEYC_UP | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEUP },
{ KEYC_UP, 0, MODEKEYCOPY_UP },
{ KEYC_WHEELUP_PANE, 0, MODEKEYCOPY_SCROLLUP },
{ KEYC_WHEELDOWN_PANE, 0, MODEKEYCOPY_SCROLLDOWN },
{ KEYC_MOUSEDRAG1_PANE, 0, MODEKEYCOPY_STARTSELECTION },
{ KEYC_MOUSEDRAGEND1_PANE, 0, MODEKEYCOPY_COPYSELECTION },
{ ' ', 0, MODEKEYCOPY_NEXTPAGE, 1 },
{ ',', 0, MODEKEYCOPY_JUMPREVERSE, 1 },
{ ';', 0, MODEKEYCOPY_JUMPAGAIN, 1 },
{ '1' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '2' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '3' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '4' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '5' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '6' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '7' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '8' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '9' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX, 1 },
{ '<' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYTOP, 1 },
{ '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM, 1 },
{ 'F', 0, MODEKEYCOPY_JUMPBACK, 1 },
{ 'N', 0, MODEKEYCOPY_SEARCHREVERSE, 1 },
{ 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE, 1 },
{ 'R', 0, MODEKEYCOPY_RECTANGLETOGGLE, 1 },
{ 'T', 0, MODEKEYCOPY_JUMPTOBACK, 1 },
{ '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION, 1 },
{ '\001' /* C-a */, 0, MODEKEYCOPY_STARTOFLINE, 1 },
{ '\002' /* C-b */, 0, MODEKEYCOPY_LEFT, 1 },
{ '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL, 1 },
{ '\005' /* C-e */, 0, MODEKEYCOPY_ENDOFLINE, 1 },
{ '\006' /* C-f */, 0, MODEKEYCOPY_RIGHT, 1 },
{ '\007' /* C-g */, 0, MODEKEYCOPY_CLEARSELECTION, 1 },
{ '\013' /* C-k */, 0, MODEKEYCOPY_COPYENDOFLINE, 1 },
{ '\016' /* C-n */, 0, MODEKEYCOPY_DOWN, 1 },
{ '\020' /* C-p */, 0, MODEKEYCOPY_UP, 1 },
{ '\022' /* C-r */, 0, MODEKEYCOPY_SEARCHUP, 1 },
{ '\023' /* C-s */, 0, MODEKEYCOPY_SEARCHDOWN, 1 },
{ '\026' /* C-v */, 0, MODEKEYCOPY_NEXTPAGE, 1 },
{ '\027' /* C-w */, 0, MODEKEYCOPY_COPYSELECTION, 1 },
{ '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL, 1 },
{ 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD, 1 },
{ 'f', 0, MODEKEYCOPY_JUMP, 1 },
{ 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORDEND, 1 },
{ 'g', 0, MODEKEYCOPY_GOTOLINE, 1 },
{ 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION, 1 },
{ 'n', 0, MODEKEYCOPY_SEARCHAGAIN, 1 },
{ 'q', 0, MODEKEYCOPY_CANCEL, 1 },
{ 'r' | KEYC_ESCAPE, 0, MODEKEYCOPY_MIDDLELINE, 1 },
{ 't', 0, MODEKEYCOPY_JUMPTO, 1 },
{ 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE, 1 },
{ 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION, 1 },
{ '{' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPARAGRAPH, 1 },
{ '}' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTPARAGRAPH, 1 },
{ KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLDOWN, 1 },
{ KEYC_DOWN | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEDOWN, 1 },
{ KEYC_DOWN, 0, MODEKEYCOPY_DOWN, 1 },
{ KEYC_LEFT, 0, MODEKEYCOPY_LEFT, 1 },
{ KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE, 1 },
{ KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE, 1 },
{ KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT, 1 },
{ KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP, 1 },
{ KEYC_UP | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEUP, 1 },
{ KEYC_UP, 0, MODEKEYCOPY_UP, 1 },
{ KEYC_WHEELUP_PANE, 0, MODEKEYCOPY_SCROLLUP, 5 },
{ KEYC_WHEELDOWN_PANE, 0, MODEKEYCOPY_SCROLLDOWN, 5 },
{ KEYC_MOUSEDRAG1_PANE, 0, MODEKEYCOPY_STARTSELECTION, 1 },
{ KEYC_MOUSEDRAGEND1_PANE, 0, MODEKEYCOPY_COPYSELECTION, 1 },
{ 0, -1, 0 }
{ 0, -1, 0, 1 }
};
struct mode_key_tree mode_key_tree_emacs_copy;
@@ -580,6 +587,7 @@ mode_key_init_trees(void)
for (ment = mtab->table; ment->mode != -1; ment++) {
mbind = xmalloc(sizeof *mbind);
mbind->key = ment->key;
mbind->repeat = ment->repeat;
mbind->mode = ment->mode;
mbind->cmd = ment->cmd;
mbind->arg = NULL;
@@ -596,7 +604,8 @@ mode_key_init(struct mode_key_data *mdata, struct mode_key_tree *mtree)
}
enum mode_key_cmd
mode_key_lookup(struct mode_key_data *mdata, key_code key, const char **arg)
mode_key_lookup(struct mode_key_data *mdata, key_code key, const char **arg,
u_int *repeat)
{
struct mode_key_binding *mbind, mtmp;
@@ -607,6 +616,8 @@ mode_key_lookup(struct mode_key_data *mdata, key_code key, const char **arg)
return (MODEKEY_NONE);
return (MODEKEY_OTHER);
}
if (repeat != NULL)
*repeat = mbind->repeat;
switch (mbind->cmd) {
case MODEKEYEDIT_SWITCHMODE:

View File

@@ -73,12 +73,15 @@ check_window_name(struct window *w)
if (!event_initialized(&w->name_event))
evtimer_set(&w->name_event, name_time_callback, w);
if (!evtimer_pending(&w->name_event, NULL)) {
log_debug("@%u name timer queued (%d left)", w->id, left);
log_debug("@%u name timer queued (%d left)", w->id,
left);
timerclear(&next);
next.tv_usec = left;
event_add(&w->name_event, &next);
} else
log_debug("@%u name timer already queued (%d left)", w->id, left);
} else {
log_debug("@%u name timer already queued (%d left)",
w->id, left);
}
return;
}
memcpy(&w->name_time, &tv, sizeof w->name_time);

View File

@@ -50,6 +50,9 @@ const char *options_table_status_position_list[] = {
const char *options_table_bell_action_list[] = {
"none", "any", "current", "other", NULL
};
const char *options_table_pane_status_list[] = {
"off", "top", "bottom", NULL
};
/* Server options. */
const struct options_table_entry options_table[] = {
@@ -692,6 +695,20 @@ const struct options_table_entry options_table[] = {
.style = "pane-border-style"
},
{ .name = "pane-border-format",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "#{?pane_active,#[reverse],}#{pane_index}#[default] "
"\"#{pane_title}\""
},
{ .name = "pane-border-status",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_pane_status_list,
.default_num = 0
},
{ .name = "pane-border-style",
.type = OPTIONS_TABLE_STYLE,
.scope = OPTIONS_TABLE_WINDOW,

View File

@@ -128,19 +128,23 @@ options_set_string(struct options *oo, const char *name, const char *fmt, ...)
{
struct options_entry *o;
va_list ap;
char *s;
s = NULL;
if ((o = options_find1(oo, name)) == NULL) {
o = xmalloc(sizeof *o);
o->name = xstrdup(name);
RB_INSERT(options_tree, &oo->tree, o);
memcpy(&o->style, &grid_default_cell, sizeof o->style);
} else if (o->type == OPTIONS_STRING)
free(o->str);
s = o->str;
va_start(ap, fmt);
o->type = OPTIONS_STRING;
xvasprintf(&o->str, fmt, ap);
va_end(ap);
free(s);
return (o);
}

View File

@@ -17,7 +17,9 @@
*/
#include <sys/types.h>
#include <sys/sysctl.h>
#include <Availability.h>
#include <event.h>
#include <libproc.h>
#include <stdlib.h>
@@ -33,18 +35,34 @@ struct event_base *osdep_event_init(void);
char *
osdep_get_name(int fd, __unused char *tty)
{
struct proc_bsdinfo bsdinfo;
#ifdef __MAC_10_7
struct proc_bsdshortinfo bsdinfo;
pid_t pgrp;
int ret;
if ((pgrp = tcgetpgrp(fd)) == -1)
return (NULL);
ret = proc_pidinfo(pgrp, PROC_PIDTBSDINFO, 0,
&bsdinfo, sizeof bsdinfo);
if (ret == sizeof bsdinfo && *bsdinfo.pbi_comm != '\0')
return (strdup(bsdinfo.pbi_comm));
return (NULL);
ret = proc_pidinfo(pgrp, PROC_PIDT_SHORTBSDINFO, 0,
&bsdinfo, sizeof bsdinfo);
if (ret == sizeof bsdinfo && *bsdinfo.pbsi_comm != '\0')
return (strdup(bsdinfo.pbsi_comm));
#else
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
size_t size;
struct kinfo_proc kp;
if ((mib[3] = tcgetpgrp(fd)) == -1)
return (NULL);
size = sizeof kp;
if (sysctl(mib, 4, &kp, &size, NULL, 0) == -1)
return (NULL);
if (*kp.kp_proc.p_comm == '\0')
return (NULL);
return (strdup(kp.kp_proc.p_comm));
#endif
}
char *

View File

@@ -16,7 +16,7 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <event.h>

2
proc.c
View File

@@ -191,9 +191,7 @@ proc_start(const char *name, struct event_base *base, int forkflag,
log_open(name);
#ifdef HAVE_SETPROCTITLE
setproctitle("%s (%s)", name, socket_path);
#endif
if (uname(&u) < 0)
memset(&u, 0, sizeof u);

View File

@@ -24,12 +24,16 @@
int screen_redraw_cell_border1(struct window_pane *, u_int, u_int);
int screen_redraw_cell_border(struct client *, u_int, u_int);
int screen_redraw_check_cell(struct client *, u_int, u_int,
int screen_redraw_check_cell(struct client *, u_int, u_int, int,
struct window_pane **);
int screen_redraw_check_is(u_int, u_int, int, struct window *,
int screen_redraw_check_is(u_int, u_int, int, int, struct window *,
struct window_pane *, struct window_pane *);
void screen_redraw_draw_borders(struct client *, int, u_int);
int screen_redraw_make_pane_status(struct client *, struct window *,
struct window_pane *);
void screen_redraw_draw_pane_status(struct client *, int);
void screen_redraw_draw_borders(struct client *, int, int, u_int);
void screen_redraw_draw_panes(struct client *, u_int);
void screen_redraw_draw_status(struct client *, u_int);
void screen_redraw_draw_number(struct client *, struct window_pane *, u_int);
@@ -50,6 +54,10 @@ void screen_redraw_draw_number(struct client *, struct window_pane *, u_int);
#define CELL_BORDERS " xqlkmjwvtun~"
#define CELL_STATUS_OFF 0
#define CELL_STATUS_TOP 1
#define CELL_STATUS_BOTTOM 2
/* Check if cell is on the border of a particular pane. */
int
screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py)
@@ -64,15 +72,15 @@ screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py)
if (wp->xoff != 0 && px == wp->xoff - 1)
return (1);
if (px == wp->xoff + wp->sx)
return (1);
return (2);
}
/* Top/bottom borders. */
if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= wp->xoff + wp->sx) {
if (wp->yoff != 0 && py == wp->yoff - 1)
return (1);
return (3);
if (py == wp->yoff + wp->sy)
return (1);
return (4);
}
/* Outside pane. */
@@ -92,7 +100,7 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py)
if (!window_pane_visible(wp))
continue;
if ((retval = screen_redraw_cell_border1(wp, px, py)) != -1)
return (retval);
return (!!retval);
}
return (0);
@@ -100,16 +108,33 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py)
/* Check if cell inside a pane. */
int
screen_redraw_check_cell(struct client *c, u_int px, u_int py,
screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
struct window_pane **wpp)
{
struct window *w = c->session->curw->window;
struct window_pane *wp;
int borders;
u_int right, line;
if (px > w->sx || py > w->sy)
return (CELL_OUTSIDE);
if (pane_status != CELL_STATUS_OFF) {
TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp))
continue;
if (pane_status == CELL_STATUS_TOP)
line = wp->yoff - 1;
else
line = wp->yoff + wp->sy;
right = wp->xoff + 2 + wp->status_size - 1;
if (py == line && px >= wp->xoff + 2 && px <= right)
return (CELL_INSIDE);
}
}
TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp))
continue;
@@ -135,8 +160,13 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py,
borders |= 8;
if (px <= w->sx && screen_redraw_cell_border(c, px + 1, py))
borders |= 4;
if (py == 0 || screen_redraw_cell_border(c, px, py - 1))
borders |= 2;
if (pane_status == CELL_STATUS_TOP) {
if (py != 0 && screen_redraw_cell_border(c, px, py - 1))
borders |= 2;
} else {
if (py == 0 || screen_redraw_cell_border(c, px, py - 1))
borders |= 2;
}
if (py <= w->sy && screen_redraw_cell_border(c, px, py + 1))
borders |= 1;
@@ -177,11 +207,18 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py,
/* Check if the border of a particular pane. */
int
screen_redraw_check_is(u_int px, u_int py, int type, struct window *w,
struct window_pane *wantwp, struct window_pane *wp)
screen_redraw_check_is(u_int px, u_int py, int type, int pane_status,
struct window *w, struct window_pane *wantwp, struct window_pane *wp)
{
int border;
/* Is this off the active pane border? */
if (screen_redraw_cell_border1(wantwp, px, py) != 1)
border = screen_redraw_cell_border1(wantwp, px, py);
if (border == 0 || border == -1)
return (0);
if (pane_status == CELL_STATUS_TOP && border == 4)
return (0);
if (pane_status == CELL_STATUS_BOTTOM && border == 3)
return (0);
/* If there are more than two panes, that's enough. */
@@ -192,6 +229,10 @@ screen_redraw_check_is(u_int px, u_int py, int type, struct window *w,
if (wp == NULL || (type == CELL_OUTSIDE || type == CELL_INSIDE))
return (1);
/* With status lines mark the entire line. */
if (pane_status != CELL_STATUS_OFF)
return (1);
/* Check if the pane covers the whole width. */
if (wp->xoff == 0 && wp->sx == w->sx) {
/* This can either be the top pane or the bottom pane. */
@@ -214,7 +255,77 @@ screen_redraw_check_is(u_int px, u_int py, int type, struct window *w,
return (0);
}
return (type);
return (1);
}
/* Update pane status. */
int
screen_redraw_make_pane_status(struct client *c, struct window *w,
struct window_pane *wp)
{
struct grid_cell gc;
const char *fmt;
struct format_tree *ft;
char *out;
size_t outlen, old_size = wp->status_size;
struct screen_write_ctx ctx;
if (wp == w->active)
style_apply(&gc, w->options, "pane-active-border-style");
else
style_apply(&gc, w->options, "pane-border-style");
fmt = options_get_string(w->options, "pane-border-format");
ft = format_create(NULL, 0);
format_defaults(ft, c, NULL, NULL, wp);
screen_free(&wp->status_screen);
screen_init(&wp->status_screen, wp->sx, 1, 0);
wp->status_screen.mode = 0;
out = format_expand(ft, fmt);
outlen = screen_write_cstrlen("%s", out);
if (outlen > wp->sx - 4)
outlen = wp->sx - 4;
screen_resize(&wp->status_screen, outlen, 1, 0);
screen_write_start(&ctx, NULL, &wp->status_screen);
screen_write_cursormove(&ctx, 0, 0);
screen_write_clearline(&ctx);
screen_write_cnputs(&ctx, outlen, &gc, "%s", out);
screen_write_stop(&ctx);
format_free(ft);
wp->status_size = outlen;
return (wp->status_size != old_size);
}
/* Draw pane status. */
void
screen_redraw_draw_pane_status(struct client *c, int pane_status)
{
struct window *w = c->session->curw->window;
struct options *oo = c->session->options;
struct tty *tty = &c->tty;
struct window_pane *wp;
int spos;
u_int yoff;
spos = options_get_number(oo, "status-position");
TAILQ_FOREACH(wp, &w->panes, entry) {
if (pane_status == CELL_STATUS_TOP)
yoff = wp->yoff - 1;
else
yoff = wp->yoff + wp->sy;
if (spos == 0)
yoff += 1;
tty_draw_line(tty, NULL, &wp->status_screen, 0, wp->xoff + 2,
yoff);
}
tty_cursor(tty, 0, 0);
}
/* Redraw entire screen. */
@@ -222,10 +333,12 @@ void
screen_redraw_screen(struct client *c, int draw_panes, int draw_status,
int draw_borders)
{
struct options *oo = c->session->options;
struct tty *tty = &c->tty;
u_int top;
int status, spos;
struct options *oo = c->session->options;
struct tty *tty = &c->tty;
struct window *w = c->session->curw->window;
struct window_pane *wp;
u_int top;
int status, pane_status, spos;
/* Suspended clients should not be updated. */
if (c->flags & CLIENT_SUSPENDED)
@@ -243,12 +356,24 @@ screen_redraw_screen(struct client *c, int draw_panes, int draw_status,
if (!status)
draw_status = 0;
/* Update pane status lines. */
pane_status = options_get_number(w->options, "pane-border-status");
if (pane_status != CELL_STATUS_OFF && (draw_borders || draw_status)) {
TAILQ_FOREACH(wp, &w->panes, entry) {
if (screen_redraw_make_pane_status(c, w, wp))
draw_borders = draw_status = 1;
}
}
/* Draw the elements. */
if (draw_borders)
screen_redraw_draw_borders(c, status, top);
screen_redraw_draw_borders(c, status, pane_status, top);
if (draw_panes)
screen_redraw_draw_panes(c, top);
if (draw_status)
screen_redraw_draw_status(c, top);
if (pane_status != CELL_STATUS_OFF && (draw_borders || draw_status))
screen_redraw_draw_pane_status(c, pane_status);
tty_reset(tty);
}
@@ -272,7 +397,8 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
/* Draw the borders. */
void
screen_redraw_draw_borders(struct client *c, int status, u_int top)
screen_redraw_draw_borders(struct client *c, int status, int pane_status,
u_int top)
{
struct session *s = c->session;
struct window *w = s->curw->window;
@@ -323,16 +449,17 @@ screen_redraw_draw_borders(struct client *c, int status, u_int top)
for (j = 0; j < tty->sy - status; j++) {
for (i = 0; i < tty->sx; i++) {
type = screen_redraw_check_cell(c, i, j, &wp);
type = screen_redraw_check_cell(c, i, j, pane_status,
&wp);
if (type == CELL_INSIDE)
continue;
if (type == CELL_OUTSIDE && small &&
i > msgx && j == msgy)
continue;
active = screen_redraw_check_is(i, j, type, w,
w->active, wp);
active = screen_redraw_check_is(i, j, type, pane_status,
w, w->active, wp);
if (server_is_marked(s, s->curw, marked_pane.wp) &&
screen_redraw_check_is(i, j, type, w,
screen_redraw_check_is(i, j, type, pane_status, w,
marked_pane.wp, wp)) {
if (active)
tty_attributes(tty, &m_active_gc, NULL);
@@ -425,9 +552,9 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp, u_int top)
memcpy(&gc, &grid_default_cell, sizeof gc);
if (w->active == wp)
colour_set_bg(&gc, active_colour);
gc.bg = active_colour;
else
colour_set_bg(&gc, colour);
gc.bg = colour;
tty_attributes(tty, &gc, wp);
for (ptr = buf; *ptr != '\0'; ptr++) {
if (*ptr < '0' || *ptr > '9')
@@ -452,9 +579,9 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp, u_int top)
draw_text:
memcpy(&gc, &grid_default_cell, sizeof gc);
if (w->active == wp)
colour_set_fg(&gc, active_colour);
gc.fg = active_colour;
else
colour_set_fg(&gc, colour);
gc.fg = colour;
tty_attributes(tty, &gc, wp);
tty_puts(tty, buf);

View File

@@ -23,27 +23,115 @@
#include "tmux.h"
void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *, int);
void screen_write_overwrite(struct screen_write_ctx *, u_int);
int screen_write_combine(struct screen_write_ctx *,
const struct utf8_data *);
static void screen_write_initctx(struct screen_write_ctx *,
struct tty_ctx *);
static void screen_write_save_last(struct screen_write_ctx *,
struct tty_ctx *);
static void screen_write_flush(struct screen_write_ctx *);
/* Initialise writing with a window. */
static int screen_write_overwrite(struct screen_write_ctx *,
struct grid_cell *, u_int);
static int screen_write_combine(struct screen_write_ctx *,
const struct utf8_data *);
static const struct grid_cell screen_write_pad_cell = {
GRID_FLAG_PADDING, 0, 8, 8, { { 0 }, 0, 0, 0 }
};
#define screen_dirty_bit(s, x, y) (((y) * screen_size_x(s)) + (x))
#define screen_dirty_clear(s, sx, sy, ex, ey) \
do { \
if (s->dirty != NULL) { \
bit_nclear(s->dirty, \
screen_dirty_bit(s, sx, sy), \
screen_dirty_bit(s, ex, ey)); \
} \
} while (0)
/* Initialize writing with a window. */
void
screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp,
struct screen *s)
{
u_int size;
char tmp[16];
const char *cp = tmp;
ctx->wp = wp;
if (wp != NULL && s == NULL)
ctx->s = wp->screen;
else
ctx->s = s;
size = screen_size_x(ctx->s) * screen_size_y(ctx->s);
if (ctx->s->dirtysize != size) {
free(ctx->s->dirty);
ctx->s->dirty = NULL;
ctx->s->dirtysize = size;
}
ctx->dirty = 0;
ctx->cells = ctx->written = ctx->skipped = 0;
if (wp == NULL)
cp = "no pane";
else
snprintf(tmp, sizeof tmp, "pane %%%u", wp->id);
log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s),
screen_size_y(ctx->s), cp);
}
/* Finish writing. */
void
screen_write_stop(__unused struct screen_write_ctx *ctx)
screen_write_stop(struct screen_write_ctx *ctx)
{
screen_write_flush(ctx);
log_debug("%s: %u of %u written (dirty %u, skipped %u)", __func__,
ctx->written, ctx->cells, ctx->cells - ctx->written, ctx->skipped);
}
/* Flush outstanding cell writes. */
static void
screen_write_flush(struct screen_write_ctx *ctx)
{
struct screen *s = ctx->s;
struct tty_ctx ttyctx;
u_int x, y, offset, cx, cy, dirty;
struct grid_cell gc;
if (ctx->dirty == 0)
return;
dirty = 0;
cx = s->cx;
cy = s->cy;
offset = 0;
for (y = 0; y < screen_size_y(s); y++) {
for (x = 0; x < screen_size_x(s); x++) {
offset++;
if (!bit_test(s->dirty, offset - 1))
continue;
bit_clear(s->dirty, offset - 1);
screen_write_cursormove(ctx, x, y);
grid_view_get_cell(s->grid, x, y, &gc);
screen_write_initctx(ctx, &ttyctx);
ttyctx.cell = &gc;
tty_write(tty_cmd_cell, &ttyctx);
ctx->written++;
if (++dirty == ctx->dirty)
break;
}
if (dirty == ctx->dirty)
break;
}
s->cx = cx;
s->cy = cy;
}
/* Reset screen state. */
@@ -64,11 +152,15 @@ screen_write_reset(struct screen_write_ctx *ctx)
/* Write character. */
void
screen_write_putc(struct screen_write_ctx *ctx, struct grid_cell *gc,
screen_write_putc(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
u_char ch)
{
utf8_set(&gc->data, ch);
screen_write_cell(ctx, gc);
struct grid_cell gc;
memcpy(&gc, gcp, sizeof gc);
utf8_set(&gc.data, ch);
screen_write_cell(ctx, &gc);
}
/* Calculate string length, with embedded formatting. */
@@ -148,75 +240,74 @@ screen_write_strlen(const char *fmt, ...)
/* Write simple string (no UTF-8 or maximum length). */
void
screen_write_puts(struct screen_write_ctx *ctx, struct grid_cell *gc,
screen_write_puts(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
screen_write_vnputs(ctx, -1, gc, fmt, ap);
screen_write_vnputs(ctx, -1, gcp, fmt, ap);
va_end(ap);
}
/* Write string with length limit (-1 for unlimited). */
void
screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen,
struct grid_cell *gc, const char *fmt, ...)
const struct grid_cell *gcp, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
screen_write_vnputs(ctx, maxlen, gc, fmt, ap);
screen_write_vnputs(ctx, maxlen, gcp, fmt, ap);
va_end(ap);
}
void
screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
struct grid_cell *gc, const char *fmt, va_list ap)
const struct grid_cell *gcp, const char *fmt, va_list ap)
{
struct grid_cell gc;
struct utf8_data *ud = &gc.data;
char *msg;
struct utf8_data ud;
u_char *ptr;
size_t left, size = 0;
enum utf8_state more;
memcpy(&gc, gcp, sizeof gc);
xvasprintf(&msg, fmt, ap);
ptr = msg;
while (*ptr != '\0') {
if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) {
if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
ptr++;
left = strlen(ptr);
if (left < (size_t)ud.size - 1)
if (left < (size_t)ud->size - 1)
break;
while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE)
while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
ptr++;
ptr++;
if (more == UTF8_DONE) {
if (maxlen > 0 &&
size + ud.width > (size_t) maxlen) {
while (size < (size_t) maxlen) {
screen_write_putc(ctx, gc, ' ');
size++;
}
break;
if (more != UTF8_DONE)
continue;
if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
while (size < (size_t)maxlen) {
screen_write_putc(ctx, &gc, ' ');
size++;
}
size += ud.width;
utf8_copy(&gc->data, &ud);
screen_write_cell(ctx, gc);
break;
}
size += ud->width;
screen_write_cell(ctx, &gc);
} else {
if (maxlen > 0 && size + 1 > (size_t) maxlen)
if (maxlen > 0 && size + 1 > (size_t)maxlen)
break;
if (*ptr == '\001')
gc->attr ^= GRID_ATTR_CHARSET;
gc.attr ^= GRID_ATTR_CHARSET;
else if (*ptr > 0x1f && *ptr < 0x7f) {
size++;
screen_write_putc(ctx, gc, *ptr);
screen_write_putc(ctx, &gc, *ptr);
}
ptr++;
}
@@ -228,22 +319,22 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
/* Write string, similar to nputs, but with embedded formatting (#[]). */
void
screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
struct grid_cell *gc, const char *fmt, ...)
const struct grid_cell *gcp, const char *fmt, ...)
{
struct grid_cell lgc;
struct utf8_data ud;
struct grid_cell gc;
struct utf8_data *ud = &gc.data;
va_list ap;
char *msg;
u_char *ptr, *last;
size_t left, size = 0;
enum utf8_state more;
memcpy(&gc, gcp, sizeof gc);
va_start(ap, fmt);
xvasprintf(&msg, fmt, ap);
va_end(ap);
memcpy(&lgc, gc, sizeof lgc);
ptr = msg;
while (*ptr != '\0') {
if (ptr[0] == '#' && ptr[1] == '[') {
@@ -255,42 +346,39 @@ screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
}
*last = '\0';
style_parse(gc, &lgc, ptr);
style_parse(gcp, &gc, ptr);
ptr = last + 1;
continue;
}
if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) {
if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
ptr++;
left = strlen(ptr);
if (left < (size_t)ud.size - 1)
if (left < (size_t)ud->size - 1)
break;
while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE)
while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
ptr++;
ptr++;
if (more == UTF8_DONE) {
if (maxlen > 0 &&
size + ud.width > (size_t) maxlen) {
while (size < (size_t) maxlen) {
screen_write_putc(ctx, gc, ' ');
size++;
}
break;
if (more != UTF8_DONE)
continue;
if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
while (size < (size_t)maxlen) {
screen_write_putc(ctx, &gc, ' ');
size++;
}
size += ud.width;
utf8_copy(&lgc.data, &ud);
screen_write_cell(ctx, &lgc);
break;
}
size += ud->width;
screen_write_cell(ctx, &gc);
} else {
if (maxlen > 0 && size + 1 > (size_t) maxlen)
if (maxlen > 0 && size + 1 > (size_t)maxlen)
break;
if (*ptr > 0x1f && *ptr < 0x7f) {
size++;
screen_write_putc(ctx, &lgc, *ptr);
screen_write_putc(ctx, &gc, *ptr);
}
ptr++;
}
@@ -344,14 +432,10 @@ screen_write_copy(struct screen_write_ctx *ctx,
}
/* Set up context for TTY command. */
void
screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
int save_last)
static void
screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
{
struct screen *s = ctx->s;
struct grid *gd = s->grid;
struct grid_cell gc;
u_int xx;
struct screen *s = ctx->s;
ttyctx->wp = ctx->wp;
@@ -360,18 +444,23 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
ttyctx->orlower = s->rlower;
ttyctx->orupper = s->rupper;
}
if (!save_last)
return;
/* Save last cell on screen. */
static void
screen_write_save_last(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
{
struct screen *s = ctx->s;
struct grid *gd = s->grid;
struct grid_cell gc;
u_int xx;
/* Save the last cell on the screen. */
memcpy(&gc, &grid_default_cell, sizeof gc);
for (xx = 1; xx <= screen_size_x(s); xx++) {
grid_view_get_cell(gd, screen_size_x(s) - xx, s->cy, &gc);
if (~gc.flags & GRID_FLAG_PADDING)
break;
}
ttyctx->last_width = xx;
memcpy(&ttyctx->last_cell, &gc, sizeof ttyctx->last_cell);
}
@@ -506,8 +595,11 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
struct tty_ctx ttyctx;
struct grid_cell gc;
u_int xx, yy;
u_int sx = screen_size_x(s), sy = screen_size_y(s);
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_initctx(ctx, &ttyctx);
screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
memcpy(&gc, &grid_default_cell, sizeof gc);
utf8_set(&gc.data, 'E');
@@ -521,7 +613,6 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
s->cy = 0;
s->rupper = 0;
s->rlower = screen_size_y(s) - 1;
tty_write(tty_cmd_alignmenttest, &ttyctx);
@@ -542,7 +633,8 @@ screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx)
if (nx == 0)
return;
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_flush(ctx);
screen_write_initctx(ctx, &ttyctx);
if (s->cx <= screen_size_x(s) - 1)
grid_view_insert_cells(s->grid, s->cx, s->cy, nx);
@@ -566,7 +658,8 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx)
if (nx == 0)
return;
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_flush(ctx);
screen_write_initctx(ctx, &ttyctx);
if (s->cx <= screen_size_x(s) - 1)
grid_view_delete_cells(s->grid, s->cx, s->cy, nx);
@@ -590,10 +683,13 @@ screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx)
if (nx == 0)
return;
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_initctx(ctx, &ttyctx);
if (s->cx <= screen_size_x(s) - 1)
if (s->cx <= screen_size_x(s) - 1) {
screen_dirty_clear(s, s->cx, s->cy, s->cx + nx - 1, s->cy);
grid_view_clear(s->grid, s->cx, s->cy, nx, 1);
} else
return;
ttyctx.num = nx;
tty_write(tty_cmd_clearcharacter, &ttyctx);
@@ -615,7 +711,8 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny)
if (ny == 0)
return;
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_flush(ctx);
screen_write_initctx(ctx, &ttyctx);
grid_view_insert_lines(s->grid, s->cy, ny);
@@ -629,7 +726,8 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny)
if (ny == 0)
return;
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_flush(ctx);
screen_write_initctx(ctx, &ttyctx);
if (s->cy < s->rupper || s->cy > s->rlower)
grid_view_insert_lines(s->grid, s->cy, ny);
@@ -656,7 +754,8 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny)
if (ny == 0)
return;
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_flush(ctx);
screen_write_initctx(ctx, &ttyctx);
grid_view_delete_lines(s->grid, s->cy, ny);
@@ -670,7 +769,8 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny)
if (ny == 0)
return;
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_flush(ctx);
screen_write_initctx(ctx, &ttyctx);
if (s->cy < s->rupper || s->cy > s->rlower)
grid_view_delete_lines(s->grid, s->cy, ny);
@@ -685,12 +785,19 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny)
void
screen_write_clearline(struct screen_write_ctx *ctx)
{
struct screen *s = ctx->s;
struct tty_ctx ttyctx;
struct screen *s = ctx->s;
struct grid_line *gl;
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s);
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_initctx(ctx, &ttyctx);
grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1);
gl = &s->grid->linedata[s->grid->hsize + s->cy];
if (gl->cellsize != 0) {
screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
grid_view_clear(s->grid, 0, s->cy, sx, 1);
} else
return;
tty_write(tty_cmd_clearline, &ttyctx);
}
@@ -699,16 +806,19 @@ screen_write_clearline(struct screen_write_ctx *ctx)
void
screen_write_clearendofline(struct screen_write_ctx *ctx)
{
struct screen *s = ctx->s;
struct tty_ctx ttyctx;
u_int sx;
struct screen *s = ctx->s;
struct grid_line *gl;
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s);
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_initctx(ctx, &ttyctx);
sx = screen_size_x(s);
if (s->cx <= sx - 1)
gl = &s->grid->linedata[s->grid->hsize + s->cy];
if (s->cx <= sx - 1 && s->cx < gl->cellsize) {
screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy);
grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
} else
return;
tty_write(tty_cmd_clearendofline, &ttyctx);
}
@@ -719,16 +829,17 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx)
{
struct screen *s = ctx->s;
struct tty_ctx ttyctx;
u_int sx;
u_int sx = screen_size_x(s);
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_initctx(ctx, &ttyctx);
sx = screen_size_x(s);
if (s->cx > sx - 1)
if (s->cx > sx - 1) {
screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
grid_view_clear(s->grid, 0, s->cy, sx, 1);
else
} else {
screen_dirty_clear(s, 0, s->cy, s->cx, s->cy);
grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
}
tty_write(tty_cmd_clearstartofline, &ttyctx);
}
@@ -755,11 +866,12 @@ screen_write_reverseindex(struct screen_write_ctx *ctx)
struct screen *s = ctx->s;
struct tty_ctx ttyctx;
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_initctx(ctx, &ttyctx);
if (s->cy == s->rupper)
if (s->cy == s->rupper) {
screen_write_flush(ctx);
grid_view_scroll_region_down(s->grid, s->rupper, s->rlower);
else if (s->cy > 0)
} else if (s->cy > 0)
s->cy--;
tty_write(tty_cmd_reverseindex, &ttyctx);
@@ -794,8 +906,9 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped)
struct screen *s = ctx->s;
struct grid_line *gl;
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s), sy = screen_size_y(s);
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_initctx(ctx, &ttyctx);
gl = &s->grid->linedata[s->grid->hsize + s->cy];
if (wrapped)
@@ -803,9 +916,11 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped)
else
gl->flags &= ~GRID_LINE_WRAPPED;
if (s->cy == s->rlower)
if (s->cy == s->rlower) {
screen_dirty_clear(s, 0, s->rupper, sx - 1, s->rupper);
screen_write_flush(ctx);
grid_view_scroll_region_up(s->grid, s->rupper, s->rlower);
else if (s->cy < screen_size_y(s) - 1)
} else if (s->cy < sy - 1)
s->cy++;
ttyctx.num = wrapped;
@@ -827,19 +942,20 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx)
{
struct screen *s = ctx->s;
struct tty_ctx ttyctx;
u_int sx, sy;
u_int sx = screen_size_x(s), sy = screen_size_y(s);
screen_write_initctx(ctx, &ttyctx, 0);
sx = screen_size_x(s);
sy = screen_size_y(s);
screen_write_initctx(ctx, &ttyctx);
/* Scroll into history if it is enabled and clearing entire screen. */
if (s->cy == 0 && s->grid->flags & GRID_HISTORY)
if (s->cy == 0 && s->grid->flags & GRID_HISTORY) {
screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
grid_view_clear_history(s->grid);
else {
if (s->cx <= sx - 1)
} else {
if (s->cx <= sx - 1) {
screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy);
grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
}
screen_dirty_clear(s, 0, s->cy + 1, sx - 1, sy - 1);
grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1));
}
@@ -852,18 +968,21 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx)
{
struct screen *s = ctx->s;
struct tty_ctx ttyctx;
u_int sx;
u_int sx = screen_size_x(s);
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_initctx(ctx, &ttyctx);
sx = screen_size_x(s);
if (s->cy > 0)
if (s->cy > 0) {
screen_dirty_clear(s, 0, 0, sx - 1, s->cy);
grid_view_clear(s->grid, 0, 0, sx, s->cy);
if (s->cx > sx - 1)
}
if (s->cx > sx - 1) {
screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
grid_view_clear(s->grid, 0, s->cy, sx, 1);
else
} else {
screen_dirty_clear(s, 0, s->cy, s->cx, s->cy);
grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
}
tty_write(tty_cmd_clearstartofscreen, &ttyctx);
}
@@ -874,10 +993,11 @@ screen_write_clearscreen(struct screen_write_ctx *ctx)
{
struct screen *s = ctx->s;
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s);
u_int sy = screen_size_y(s);
u_int sx = screen_size_x(s), sy = screen_size_y(s);
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_initctx(ctx, &ttyctx);
screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
/* Scroll into history if it is enabled. */
if (s->grid->flags & GRID_HISTORY)
@@ -896,7 +1016,7 @@ screen_write_clearhistory(struct screen_write_ctx *ctx)
struct grid *gd = s->grid;
grid_move_lines(gd, 0, gd->hsize, gd->sy);
gd->hsize = 0;
gd->hscrolled = gd->hsize = 0;
}
/* Write cell data. */
@@ -907,8 +1027,13 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
struct grid *gd = s->grid;
struct tty_ctx ttyctx;
u_int width, xx, last;
struct grid_cell tmp_gc;
int insert;
u_int sx = screen_size_x(s), sy = screen_size_y(s);
struct grid_line *gl;
struct grid_cell tmp_gc, now_gc;
struct grid_cell_entry *gce;
int insert, skip, selected, wrapped = 0;
ctx->cells++;
/* Ignore padding. */
if (gc->flags & GRID_FLAG_PADDING)
@@ -919,10 +1044,8 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
* If this is a wide character and there is no room on the screen, for
* the entire character, don't print it.
*/
if (!(s->mode & MODE_WRAP)
&& (width > 1 && (width > screen_size_x(s) ||
(s->cx != screen_size_x(s)
&& s->cx > screen_size_x(s) - width))))
if (!(s->mode & MODE_WRAP) && (width > 1 &&
(width > sx || (s->cx != sx && s->cx > sx - width))))
return;
/*
@@ -931,84 +1054,149 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
*/
if (width == 0) {
if (screen_write_combine(ctx, &gc->data) == 0) {
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_initctx(ctx, &ttyctx);
tty_write(tty_cmd_utf8character, &ttyctx);
}
return;
}
/* Initialise the redraw context, saving the last cell. */
screen_write_initctx(ctx, &ttyctx, 1);
/* Initialise the redraw context. */
screen_write_initctx(ctx, &ttyctx);
/* If in insert mode, make space for the cells. */
if ((s->mode & MODE_INSERT) && s->cx <= screen_size_x(s) - width) {
xx = screen_size_x(s) - s->cx - width;
if ((s->mode & MODE_INSERT) && s->cx <= sx - width) {
xx = sx - s->cx - width;
grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx);
insert = 1;
} else
insert = 0;
skip = !insert;
/* Check this will fit on the current line and wrap if not. */
if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) {
if ((s->mode & MODE_WRAP) && s->cx > sx - width) {
screen_write_flush(ctx);
screen_write_save_last(ctx, &ttyctx);
screen_write_linefeed(ctx, 1);
s->cx = 0; /* carriage return */
skip = 0;
wrapped = 1;
}
/* Sanity check cursor position. */
if (s->cx > screen_size_x(s) - width || s->cy > screen_size_y(s) - 1)
if (s->cx > sx - width || s->cy > sy - 1)
return;
/* Handle overwriting of UTF-8 characters. */
screen_write_overwrite(ctx, width);
gl = &s->grid->linedata[s->grid->hsize + s->cy];
if (gl->flags & GRID_LINE_EXTENDED) {
grid_view_get_cell(gd, s->cx, s->cy, &now_gc);
if (screen_write_overwrite(ctx, &now_gc, width))
skip = 0;
}
/*
* If the new character is UTF-8 wide, fill in padding cells. Have
* already ensured there is enough room.
*/
memcpy(&tmp_gc, &grid_default_cell, sizeof tmp_gc);
tmp_gc.flags |= GRID_FLAG_PADDING;
tmp_gc.data.width = 0;
for (xx = s->cx + 1; xx < s->cx + width; xx++)
grid_view_set_cell(gd, xx, s->cy, &tmp_gc);
for (xx = s->cx + 1; xx < s->cx + width; xx++) {
grid_view_set_cell(gd, xx, s->cy, &screen_write_pad_cell);
skip = 0;
}
/* Set the cell. */
grid_view_set_cell(gd, s->cx, s->cy, gc);
/* If no change, do not draw. */
if (skip) {
if (s->cx >= gl->cellsize)
skip = grid_cells_equal(gc, &grid_default_cell);
else {
gce = &gl->celldata[s->cx];
if (gce->flags & GRID_FLAG_EXTENDED)
skip = 0;
else if (gc->flags != (gce->flags & ~GRID_FLAG_EXTENDED))
skip = 0;
else if (gc->attr != gce->data.attr)
skip = 0;
else if (gc->fg != gce->data.fg)
skip = 0;
else if (gc->bg != gce->data.bg)
skip = 0;
else if (gc->data.width != 1 || gce->data.data != gc->data.data[0])
skip = 0;
}
}
/* Update the selection the flag and set the cell. */
selected = screen_check_selection(s, s->cx, s->cy);
if (selected && ~gc->flags & GRID_FLAG_SELECTED) {
skip = 0;
memcpy(&tmp_gc, gc, sizeof tmp_gc);
tmp_gc.flags |= GRID_FLAG_SELECTED;
grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc);
} else if (!selected && gc->flags & GRID_FLAG_SELECTED) {
skip = 0;
memcpy(&tmp_gc, gc, sizeof tmp_gc);
tmp_gc.flags &= ~GRID_FLAG_SELECTED;
grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc);
} else if (!skip)
grid_view_set_cell(gd, s->cx, s->cy, gc);
/*
* Move the cursor. If not wrapping, stick at the last character and
* replace it.
*/
last = !(s->mode & MODE_WRAP);
if (s->cx <= screen_size_x(s) - last - width)
if (s->cx <= sx - last - width)
s->cx += width;
else
s->cx = screen_size_x(s) - last;
s->cx = sx - last;
/* Draw to the screen if necessary. */
/* Create space for character in insert mode. */
if (insert) {
if (!wrapped)
screen_write_flush(ctx);
ttyctx.num = width;
tty_write(tty_cmd_insertcharacter, &ttyctx);
}
if (screen_check_selection(s, s->cx - width, s->cy)) {
/* Write to the screen. */
if (selected) {
memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc);
utf8_copy(&tmp_gc.data, &gc->data);
tmp_gc.attr = tmp_gc.attr & ~GRID_ATTR_CHARSET;
tmp_gc.attr |= gc->attr & GRID_ATTR_CHARSET;
tmp_gc.flags = gc->flags;
tmp_gc.flags &= ~(GRID_FLAG_FGRGB|GRID_FLAG_BGRGB);
tmp_gc.flags &= ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
tmp_gc.flags |= s->sel.cell.flags &
(GRID_FLAG_FG256|GRID_FLAG_BG256);
screen_write_flush(ctx);
ttyctx.cell = &tmp_gc;
tty_write(tty_cmd_cell, &ttyctx);
} else {
ttyctx.cell = gc;
tty_write(tty_cmd_cell, &ttyctx);
}
ctx->written++;
} else if (!skip) {
if (wrapped) {
ttyctx.cell = gc;
tty_write(tty_cmd_cell, &ttyctx);
ctx->written++;
} else {
/*
* If wp is NULL, we are not updating the terminal and
* don't care about actually writing the cells
* (tty_write will just return). So don't even bother
* allocating the dirty array.
*/
if (ctx->wp != NULL && s->dirty == NULL) {
log_debug("%s: allocating %u bits", __func__,
s->dirtysize);
s->dirty = bit_alloc(s->dirtysize);
}
if (s->dirty != NULL) {
bit_set(s->dirty, screen_dirty_bit(s,
ttyctx.ocx, ttyctx.ocy));
ctx->dirty++;
}
}
} else
ctx->skipped++;
}
/* Combine a UTF-8 zero-width character onto the previous. */
int
static int
screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud)
{
struct screen *s = ctx->s;
@@ -1049,16 +1237,17 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud)
* character, it is necessary to also overwrite any other cells which covered
* by the same character.
*/
void
screen_write_overwrite(struct screen_write_ctx *ctx, u_int width)
static int
screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
u_int width)
{
struct screen *s = ctx->s;
struct grid *gd = s->grid;
struct grid_cell gc;
struct grid_cell tmp_gc;
u_int xx;
int done = 0;
grid_view_get_cell(gd, s->cx, s->cy, &gc);
if (gc.flags & GRID_FLAG_PADDING) {
if (gc->flags & GRID_FLAG_PADDING) {
/*
* A padding cell, so clear any following and leading padding
* cells back to the character. Don't overwrite the current
@@ -1066,27 +1255,33 @@ screen_write_overwrite(struct screen_write_ctx *ctx, u_int width)
*/
xx = s->cx + 1;
while (--xx > 0) {
grid_view_get_cell(gd, xx, s->cy, &gc);
if (~gc.flags & GRID_FLAG_PADDING)
grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
if (~tmp_gc.flags & GRID_FLAG_PADDING)
break;
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
}
/* Overwrite the character at the start of this padding. */
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
done = 1;
}
/*
* Overwrite any padding cells that belong to a UTF-8 character
* we'll be overwriting with the current character.
* Overwrite any padding cells that belong to any UTF-8 characters we'll be
* overwriting with the current character.
*/
xx = s->cx + width - 1;
while (++xx < screen_size_x(s)) {
grid_view_get_cell(gd, xx, s->cy, &gc);
if (~gc.flags & GRID_FLAG_PADDING)
break;
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
if (width != 1 || gc->data.width != 1 || gc->flags & GRID_FLAG_PADDING) {
xx = s->cx + width - 1;
while (++xx < screen_size_x(s)) {
grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
if (~tmp_gc.flags & GRID_FLAG_PADDING)
break;
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
done = 1;
}
}
return (done);
}
void
@@ -1094,7 +1289,7 @@ screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len)
{
struct tty_ctx ttyctx;
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_initctx(ctx, &ttyctx);
ttyctx.ptr = str;
ttyctx.num = len;
@@ -1104,9 +1299,9 @@ screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len)
void
screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len)
{
struct tty_ctx ttyctx;
struct tty_ctx ttyctx;
screen_write_initctx(ctx, &ttyctx, 0);
screen_write_initctx(ctx, &ttyctx);
ttyctx.ptr = str;
ttyctx.num = len;

View File

@@ -38,6 +38,9 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
s->ccolour = xstrdup("");
s->tabs = NULL;
s->dirty = NULL;
s->dirtysize = 0;
screen_reinit(s);
}
@@ -64,6 +67,7 @@ screen_reinit(struct screen *s)
void
screen_free(struct screen *s)
{
free(s->dirty);
free(s->tabs);
free(s->title);
free(s->ccolour);
@@ -146,7 +150,7 @@ screen_resize_x(struct screen *s, u_int sx)
/*
* Treat resizing horizontally simply: just ensure the cursor is
* on-screen and change the size. Don't bother to truncate any lines -
* then the data should be accessible if the size is then incrased.
* then the data should be accessible if the size is then increased.
*
* The only potential wrinkle is if UTF-8 double-width characters are
* left in the last column, but UTF-8 terminals should deal with this
@@ -173,8 +177,9 @@ screen_resize_y(struct screen *s, u_int sy)
* If the height is decreasing, delete lines from the bottom until
* hitting the cursor, then push lines from the top into the history.
*
* When increasing, pull as many lines as possible from the history to
* the top, then fill the remaining with blanks at the bottom.
* When increasing, pull as many lines as possible from scrolled
* history (not explicitly cleared from view) to the top, then fill the
* remaining with blanks at the bottom.
*/
/* Size decreasing. */
@@ -196,9 +201,10 @@ screen_resize_y(struct screen *s, u_int sy)
* lines from the top.
*/
available = s->cy;
if (gd->flags & GRID_HISTORY)
if (gd->flags & GRID_HISTORY) {
gd->hscrolled += needed;
gd->hsize += needed;
else if (needed > 0 && available > 0) {
} else if (needed > 0 && available > 0) {
if (available > needed)
available = needed;
grid_view_delete_lines(gd, 0, available);
@@ -215,13 +221,14 @@ screen_resize_y(struct screen *s, u_int sy)
needed = sy - oldy;
/*
* Try to pull as much as possible out of the history, if is
* Try to pull as much as possible out of scrolled history, if is
* is enabled.
*/
available = gd->hsize;
available = gd->hscrolled;
if (gd->flags & GRID_HISTORY && available > 0) {
if (available > needed)
available = needed;
gd->hscrolled -= available;
gd->hsize -= available;
s->cy += available;
} else

View File

@@ -182,6 +182,7 @@ server_client_lost(struct client *c)
c->flags |= CLIENT_DEAD;
server_clear_identify(c, NULL);
status_prompt_clear(c);
status_message_clear(c);
@@ -604,16 +605,16 @@ server_client_handle_key(struct client *c, key_code key)
return;
window_unzoom(w);
wp = window_pane_at_index(w, key - '0');
if (wp != NULL && window_pane_visible(wp))
window_set_active_pane(w, wp);
server_clear_identify(c);
if (wp != NULL && !window_pane_visible(wp))
wp = NULL;
server_clear_identify(c, wp);
return;
}
/* Handle status line. */
if (!(c->flags & CLIENT_READONLY)) {
status_message_clear(c);
server_clear_identify(c);
server_clear_identify(c, NULL);
}
if (c->prompt_string != NULL) {
if (!(c->flags & CLIENT_READONLY))
@@ -762,11 +763,13 @@ server_client_loop(void)
}
}
/* Check if pane should be resized. */
void
server_client_check_resize(struct window_pane *wp)
static void
server_client_resize_event(__unused int fd, __unused short events, void *data)
{
struct winsize ws;
struct window_pane *wp = data;
struct winsize ws;
evtimer_del(&wp->resize_timer);
if (!(wp->flags & PANE_RESIZE))
return;
@@ -791,6 +794,36 @@ server_client_check_resize(struct window_pane *wp)
wp->flags &= ~PANE_RESIZE;
}
/* Check if pane should be resized. */
void
server_client_check_resize(struct window_pane *wp)
{
struct timeval tv = { .tv_usec = 250000 };
if (!(wp->flags & PANE_RESIZE))
return;
if (!event_initialized(&wp->resize_timer))
evtimer_set(&wp->resize_timer, server_client_resize_event, wp);
/*
* The first resize should happen immediately, so if the timer is not
* running, do it now.
*/
if (!evtimer_pending(&wp->resize_timer, NULL))
server_client_resize_event(-1, 0, wp);
/*
* If the pane is in the alternate screen, let the timer expire and
* resize to give the application a chance to redraw. If not, keep
* pushing the timer back.
*/
if (wp->saved_grid != NULL && evtimer_pending(&wp->resize_timer, NULL))
return;
evtimer_del(&wp->resize_timer);
evtimer_add(&wp->resize_timer, &tv);
}
/* Check whether pane should be focused. */
void
server_client_check_focus(struct window_pane *wp)
@@ -862,10 +895,7 @@ server_client_reset_state(struct client *c)
struct options *oo = c->session->options;
int status, mode, o;
if (c->flags & CLIENT_SUSPENDED)
return;
if (c->flags & CLIENT_CONTROL)
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return;
tty_region(&c->tty, 0, c->tty.sy - 1);
@@ -929,7 +959,7 @@ server_client_check_redraw(struct client *c)
struct session *s = c->session;
struct tty *tty = &c->tty;
struct window_pane *wp;
int flags, redraw;
int flags, masked, redraw;
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return;
@@ -969,15 +999,15 @@ server_client_check_redraw(struct client *c)
}
}
if (c->flags & CLIENT_BORDERS) {
masked = c->flags & (CLIENT_BORDERS|CLIENT_STATUS);
if (masked != 0)
tty_update_mode(tty, tty->mode, NULL);
if (masked == CLIENT_BORDERS)
screen_redraw_screen(c, 0, 0, 1);
}
if (c->flags & CLIENT_STATUS) {
tty_update_mode(tty, tty->mode, NULL);
else if (masked == CLIENT_STATUS)
screen_redraw_screen(c, 0, 1, 0);
}
else if (masked != 0)
screen_redraw_screen(c, 0, 1, 1);
tty->flags = (tty->flags & ~(TTY_FREEZE|TTY_NOCURSOR)) | flags;
tty_update_mode(tty, tty->mode, NULL);
@@ -1098,12 +1128,13 @@ server_client_dispatch(struct imsg *imsg, void *arg)
if (gettimeofday(&c->activity_time, NULL) != 0)
fatal("gettimeofday failed");
if (s != NULL)
session_update_activity(s, &c->activity_time);
tty_start_tty(&c->tty);
server_redraw_client(c);
recalculate_sizes();
if (s != NULL)
session_update_activity(s, &c->activity_time);
break;
case MSG_SHELL:
if (datalen != 0)

View File

@@ -442,21 +442,23 @@ server_set_identify(struct client *c)
}
void
server_clear_identify(struct client *c)
server_clear_identify(struct client *c, struct window_pane *wp)
{
if (c->flags & CLIENT_IDENTIFY) {
c->flags &= ~CLIENT_IDENTIFY;
c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR);
server_redraw_client(c);
}
if (~c->flags & CLIENT_IDENTIFY)
return;
c->flags &= ~CLIENT_IDENTIFY;
if (c->identify_callback != NULL)
c->identify_callback(c, wp);
c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR);
server_redraw_client(c);
}
void
server_callback_identify(__unused int fd, __unused short events, void *data)
{
struct client *c = data;
server_clear_identify(c);
server_clear_identify(data, NULL);
}
/* Set stdin callback. */

View File

@@ -260,7 +260,7 @@ server_update_socket(void)
if (stat(socket_path, &sb) != 0)
return;
mode = sb.st_mode;
mode = sb.st_mode & ACCESSPERMS;
if (n != 0) {
if (mode & S_IRUSR)
mode |= S_IXUSR;

View File

@@ -257,16 +257,19 @@ status_get_window_at(struct client *c, u_int x)
struct session *s = c->session;
struct winlink *wl;
struct options *oo;
size_t len;
const char *sep;
size_t seplen;
x += c->wlmouse;
RB_FOREACH(wl, winlinks, &s->windows) {
oo = wl->window->options;
len = strlen(options_get_string(oo, "window-status-separator"));
sep = options_get_string(oo, "window-status-separator");
seplen = screen_write_cstrlen("%s", sep);
if (x < wl->status_width)
return (wl->window);
x -= wl->status_width + len;
x -= wl->status_width + seplen;
}
return (NULL);
}
@@ -344,7 +347,7 @@ status_redraw(struct client *c)
oo = wl->window->options;
sep = options_get_string(oo, "window-status-separator");
seplen = screen_write_strlen("%s", sep);
seplen = screen_write_cstrlen("%s", sep);
wlwidth += wl->status_width + seplen;
}
@@ -359,7 +362,7 @@ status_redraw(struct client *c)
oo = wl->window->options;
sep = options_get_string(oo, "window-status-separator");
screen_write_nputs(&ctx, -1, &stdgc, "%s", sep);
screen_write_cnputs(&ctx, -1, &stdgc, "%s", sep);
}
screen_write_stop(&ctx);
@@ -815,7 +818,7 @@ status_prompt_key(struct client *c, key_code key)
size_t size, n, off, idx, bufsize;
size = strlen(c->prompt_buffer);
switch (mode_key_lookup(&c->prompt_mdata, key, NULL)) {
switch (mode_key_lookup(&c->prompt_mdata, key, NULL, NULL)) {
case MODEKEYEDIT_CURSORLEFT:
if (c->prompt_index > 0) {
c->prompt_index--;

105
style.c
View File

@@ -33,7 +33,8 @@ style_parse(const struct grid_cell *defgc, struct grid_cell *gc,
char tmp[32];
int val;
size_t end;
u_char fg, bg, attr, flags;
int fg, bg;
u_char attr, flags;
if (*in == '\0')
return (0);
@@ -56,38 +57,20 @@ style_parse(const struct grid_cell *defgc, struct grid_cell *gc,
fg = defgc->fg;
bg = defgc->bg;
attr = defgc->attr;
flags &= ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
flags |=
defgc->flags & (GRID_FLAG_FG256|GRID_FLAG_BG256);
flags = defgc->flags;
} else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) {
if ((val = colour_fromstring(tmp + 3)) == -1)
goto error;
if (*in == 'f' || *in == 'F') {
if (val != 8) {
if (val & 0x100) {
flags |= GRID_FLAG_FG256;
val &= ~0x100;
} else
flags &= ~GRID_FLAG_FG256;
if (val != 8)
fg = val;
} else {
else
fg = defgc->fg;
flags &= ~GRID_FLAG_FG256;
flags |= defgc->flags & GRID_FLAG_FG256;
}
} else if (*in == 'b' || *in == 'B') {
if (val != 8) {
if (val & 0x100) {
flags |= GRID_FLAG_BG256;
val &= ~0x100;
} else
flags &= ~GRID_FLAG_BG256;
if (val != 8)
bg = val;
} else {
else
bg = defgc->bg;
flags &= ~GRID_FLAG_BG256;
flags |= defgc->flags & GRID_FLAG_BG256;
}
} else
goto error;
} else if (strcasecmp(tmp, "none") == 0)
@@ -120,27 +103,19 @@ error:
const char *
style_tostring(struct grid_cell *gc)
{
int c, off = 0, comma = 0;
int off = 0, comma = 0;
static char s[256];
*s = '\0';
if (gc->fg != 8 || gc->flags & GRID_FLAG_FG256) {
if (gc->flags & GRID_FLAG_FG256)
c = gc->fg | 0x100;
else
c = gc->fg;
off += xsnprintf(s, sizeof s, "fg=%s", colour_tostring(c));
if (gc->fg != 8) {
off += xsnprintf(s, sizeof s, "fg=%s", colour_tostring(gc->fg));
comma = 1;
}
if (gc->bg != 8 || gc->flags & GRID_FLAG_BG256) {
if (gc->flags & GRID_FLAG_BG256)
c = gc->bg | 0x100;
else
c = gc->bg;
if (gc->bg != 8) {
off += xsnprintf(s + off, sizeof s - off, "%sbg=%s",
comma ? "," : "", colour_tostring(c));
comma ? "," : "", colour_tostring(gc->bg));
comma = 1;
}
@@ -177,9 +152,9 @@ style_update_new(struct options *oo, const char *name, const char *newname)
value = o->num;
if (strstr(name, "-bg") != NULL)
colour_set_bg(gc, value);
gc->bg = value;
else if (strstr(name, "-fg") != NULL)
colour_set_fg(gc, value);
gc->fg = value;
else if (strstr(name, "-attr") != NULL)
gc->attr = value;
}
@@ -189,23 +164,15 @@ void
style_update_old(struct options *oo, const char *name, struct grid_cell *gc)
{
char newname[128];
int c, size;
int size;
size = strrchr(name, '-') - name;
if (gc->flags & GRID_FLAG_BG256)
c = gc->bg | 0x100;
else
c = gc->bg;
xsnprintf(newname, sizeof newname, "%.*s-bg", size, name);
options_set_number(oo, newname, c);
options_set_number(oo, newname, gc->bg);
if (gc->flags & GRID_FLAG_FG256)
c = gc->fg | 0x100;
else
c = gc->fg;
xsnprintf(newname, sizeof newname, "%.*s-fg", size, name);
options_set_number(oo, newname, c);
options_set_number(oo, newname, gc->fg);
xsnprintf(newname, sizeof newname, "%.*s-attr", size, name);
options_set_number(oo, newname, gc->attr);
@@ -219,14 +186,8 @@ style_apply(struct grid_cell *gc, struct options *oo, const char *name)
memcpy(gc, &grid_default_cell, sizeof *gc);
gcp = options_get_style(oo, name);
if (gcp->flags & GRID_FLAG_FG256)
colour_set_fg(gc, gcp->fg | 0x100);
else
colour_set_fg(gc, gcp->fg);
if (gcp->flags & GRID_FLAG_BG256)
colour_set_bg(gc, gcp->bg | 0x100);
else
colour_set_bg(gc, gcp->bg);
gc->fg = gcp->fg;
gc->bg = gcp->bg;
gc->attr |= gcp->attr;
}
@@ -237,18 +198,10 @@ style_apply_update(struct grid_cell *gc, struct options *oo, const char *name)
struct grid_cell *gcp;
gcp = options_get_style(oo, name);
if (gcp->fg != 8 || gcp->flags & GRID_FLAG_FG256) {
if (gcp->flags & GRID_FLAG_FG256)
colour_set_fg(gc, gcp->fg | 0x100);
else
colour_set_fg(gc, gcp->fg);
}
if (gcp->bg != 8 || gcp->flags & GRID_FLAG_BG256) {
if (gcp->flags & GRID_FLAG_BG256)
colour_set_bg(gc, gcp->bg | 0x100);
else
colour_set_bg(gc, gcp->bg);
}
if (gcp->fg != 8)
gc->fg = gcp->fg;
if (gcp->bg != 8)
gc->bg = gcp->bg;
if (gcp->attr != 0)
gc->attr |= gcp->attr;
}
@@ -257,10 +210,10 @@ style_apply_update(struct grid_cell *gc, struct options *oo, const char *name)
int
style_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
{
return gc1->fg == gc2->fg &&
gc1->bg == gc2->bg &&
(gc1->flags & ~GRID_FLAG_PADDING) ==
(gc2->flags & ~GRID_FLAG_PADDING) &&
(gc1->attr & ~GRID_ATTR_CHARSET) ==
(gc2->attr & ~GRID_ATTR_CHARSET);
return (gc1->fg == gc2->fg &&
gc1->bg == gc2->bg &&
(gc1->flags & ~GRID_FLAG_PADDING) ==
(gc2->flags & ~GRID_FLAG_PADDING) &&
(gc1->attr & ~GRID_ATTR_CHARSET) ==
(gc2->attr & ~GRID_ATTR_CHARSET));
}

121
tmux.1
View File

@@ -777,7 +777,9 @@ section.
If
.Ar target-session
is specified, list only clients connected to that session.
.It Ic list-commands
.It Xo Ic list-commands
.Op Fl F Ar format
.Xc
.D1 (alias: Ic lscm )
List the syntax of all commands supported by
.Nm .
@@ -917,10 +919,18 @@ display the log for
and
.Fl T
show debugging information about jobs and terminals.
.It Ic source-file Ar path
.It Xo Ic source-file
.Op Fl q
.Ar path
.Xc
.D1 (alias: Ic source )
Execute commands from
.Ar path .
If
.Fl q
is given, no error will be returned if
.Ar path
does not exist.
.It Ic start-server
.D1 (alias: Ic start )
Start the
@@ -981,7 +991,7 @@ bind-key -Troot a switch-client -Ttable1
.Sh WINDOWS AND PANES
A
.Nm
window may be in one of several modes.
window may be in one of two modes.
The default permits direct access to the terminal attached to the window.
The other is copy mode, which permits a section of a window or its
history to be copied to a
@@ -1029,6 +1039,7 @@ The following keys are supported as appropriate for the mode:
.It Li "Jump to backward" Ta "T" Ta ""
.It Li "Jump to forward" Ta "t" Ta ""
.It Li "Next page" Ta "C-f" Ta "Page down"
.It Li "Next paragraph" Ta "}" Ta "M-}"
.It Li "Next space" Ta "W" Ta ""
.It Li "Next space, end of word" Ta "E" Ta ""
.It Li "Next word" Ta "w" Ta ""
@@ -1036,6 +1047,7 @@ The following keys are supported as appropriate for the mode:
.It Li "Other end of selection" Ta "o" Ta ""
.It Li "Paste buffer" Ta "p" Ta "C-y"
.It Li "Previous page" Ta "C-b" Ta "Page up"
.It Li "Previous paragraph" Ta "{" Ta "M-{"
.It Li "Previous space" Ta "B" Ta ""
.It Li "Previous word" Ta "b" Ta "M-b"
.It Li "Quit mode" Ta "q" Ta "Escape"
@@ -1450,7 +1462,11 @@ flag, see the
.Sx FORMATS
section.
This command works only if at least one client is attached.
.It Ic display-panes Op Fl t Ar target-client
.It Xo
.Ic display-panes
.Op Fl t Ar target-client
.Op Ar template
.Xc
.D1 (alias: Ic displayp )
Display a visible indicator of each pane shown by
.Ar target-client .
@@ -1460,11 +1476,18 @@ See the
and
.Ic display-panes-active-colour
session options.
While the indicator is on screen, a pane may be selected with the
While the indicator is on screen, a pane may be chosen with the
.Ql 0
to
.Ql 9
keys.
keys, which will cause
.Ar template
to be executed as a command with
.Ql %%
substituted by the pane ID.
The default
.Ar template
is "select-pane -t '%%'".
.It Xo Ic find-window
.Op Fl CNT
.Op Fl F Ar format
@@ -1992,6 +2015,13 @@ The
.Fl b
option causes the new pane to be created to the left of or above
.Ar target-pane .
The
.Fl f
option creates a new pane spanning the full window height (with
.Fl h )
or full window width (with
.Fl v ) ,
instead of splitting the active pane.
All other options have the same meaning as for the
.Ic new-window
command.
@@ -2107,6 +2137,7 @@ Commands related to key bindings are as follows:
.Bl -tag -width Ds
.It Xo Ic bind-key
.Op Fl cnr
.Op Fl R Ar repeat-count
.Op Fl t Ar mode-table
.Op Fl T Ar key-table
.Ar key Ar command Op Ar arguments
@@ -2165,6 +2196,14 @@ is bound in
the binding for command mode with
.Fl c
or for normal mode without.
For keys in the
.Em vi-copy
or
.Em emacs-copy
tables,
.Fl R
specifies how many times the command should be repeated.
.Pp
See the
.Sx WINDOWS AND PANES
section and the
@@ -2776,19 +2815,17 @@ will be passed through
and formats (see
.Sx FORMATS )
will be expanded.
It may also contain any of the following special character sequences:
.Bl -column "Character pair" "Replaced with" -offset indent
.It Sy "Character pair" Ta Sy "Replaced with"
.It Li "#[attributes]" Ta "Colour or attribute change"
.It Li "##" Ta "A literal" Ql #
.El
It may also contain the special character sequence #[] to change the colour
or attributes, for example
.Ql #[fg=red,bright]
to set a bright red foreground.
See the
.Ic message-command-style
option for a description of colours and attributes.
.Pp
For details on how the names and titles can be set see the
.Sx "NAMES AND TITLES"
section.
For a list of allowed attributes see the
.Ic message-command-style
option.
.Pp
Examples are:
.Bd -literal -offset indent
@@ -3067,6 +3104,14 @@ Like
.Ic base-index ,
but set the starting index for pane numbers.
.Pp
.It Ic pane-border-format Ar format
Set the text shown in pane border status lines.
.Pp
.It Xo Ic pane-border-status
.Op Ic off | top | bottom
.Xc
Turn pane border status lines off or set their position.
.Pp
.It Ic pane-border-style Ar style
Set the pane border style for panes aside from the active pane.
For how to specify
@@ -3223,9 +3268,35 @@ shows only the option value, not the name.
.Nm
allows commands to run on various triggers, called
.Em hooks .
Each hook has a
.Em name .
The following hooks are available:
Each
.Nm
command has a
.Em before
hook and an
.Em after
hook and there are a number of hooks not associated with commands.
.Pp
A command's before hook is run before the command is executed and its after
hook is run afterwards, except when the command is run as part of a hook
itself.
Before hooks are named using the
.Ql before-
prefix and after hooks the
.Ql after-
prefix.
For example, the following command adds a hook to select the even-vertical
layout after every
.Ic split-window :
.Bd -literal -offset indent
set-hook after-split-window "selectl even-vertical"
.Ed
.Pp
Or to write when each new window is created to a file:
.Bd -literal -offset indent
set-hook before-new-window 'run "date >>/tmp/log"'
.Ed
.Pp
In addition, the following hooks are available:
.Bl -tag -width "XXXXXXXXXXXXXXXX"
.It alert-activity
Run when a window has activity.
@@ -3436,6 +3507,7 @@ The following variables are available, where appropriate:
.It Li "alternate_on" Ta "" Ta "If pane is in alternate screen"
.It Li "alternate_saved_x" Ta "" Ta "Saved cursor X in alternate screen"
.It Li "alternate_saved_y" Ta "" Ta "Saved cursor Y in alternate screen"
.It Li "buffer_name" Ta "" Ta "Name of buffer"
.It Li "buffer_sample" Ta "" Ta "Sample of start of buffer"
.It Li "buffer_size" Ta "" Ta "Size of the specified buffer in bytes"
.It Li "client_activity" Ta "" Ta "Integer time client last had activity"
@@ -3452,7 +3524,11 @@ The following variables are available, where appropriate:
.It Li "client_tty" Ta "" Ta "Pseudo terminal of client"
.It Li "client_utf8" Ta "" Ta "1 if client supports utf8"
.It Li "client_width" Ta "" Ta "Width of client"
.It Li "command_hooked" Ta "" Ta "Name of command hooked, if any"
.It Li "command_name" Ta "" Ta "Name of command in use, if any"
.It Li "command_list_name" Ta "" Ta "Command name if listing commands"
.It Li "command_list_alias" Ta "" Ta "Command alias if listing commands"
.It Li "command_list_usage" Ta "" Ta "Command usage if listing commands"
.It Li "cursor_flag" Ta "" Ta "Pane cursor flag"
.It Li "cursor_x" Ta "" Ta "Cursor X position in pane"
.It Li "cursor_y" Ta "" Ta "Cursor Y position in pane"
@@ -3506,9 +3582,10 @@ The following variables are available, where appropriate:
.It Li "session_name" Ta "#S" Ta "Name of session"
.It Li "session_width" Ta "" Ta "Width of session"
.It Li "session_windows" Ta "" Ta "Number of windows in session"
.It Li "socket_path" Ta "" "Server socket path"
.It Li "socket_path" Ta "" Ta "Server socket path"
.It Li "start_time" Ta "" Ta "Server start time"
.It Li "window_activity" Ta "" Ta "Integer time of window last activity"
.It Li "window_activity_flag" Ta "" Ta "1 if window has activity"
.It Li "window_active" Ta "" Ta "1 if window active"
.It Li "window_bell_flag" Ta "" Ta "1 if window has bell"
.It Li "window_find_matches" Ta "" Ta "Matched data from the find-window"
@@ -3744,9 +3821,7 @@ Before the command is executed, the first occurrence of the string
.Ql %%
and all occurrences of
.Ql %1
are replaced by the response to the first prompt, the second
.Ql %%
and all
are replaced by the response to the first prompt, all
.Ql %2
are replaced with the response to the second prompt, and so on for further
prompts.
@@ -3819,7 +3894,7 @@ and so on.
When the
.Ic buffer-limit
option is reached, the oldest automatically named buffer is deleted.
Explicitly named are not subject to
Explicitly named buffers are not subject to
.Ic buffer-limit
and may be deleted with
.Ic delete-buffer

15
tmux.c
View File

@@ -46,17 +46,13 @@ const char *socket_path;
__dead void usage(void);
static char *make_label(const char *);
#ifndef HAVE___PROGNAME
char *__progname = (char *) "tmux";
#endif
__dead void
usage(void)
{
fprintf(stderr,
"usage: %s [-2CluvV] [-c shell-command] [-f file] [-L socket-name]\n"
" [-S socket-path] [command [flags]]\n",
__progname);
getprogname());
exit(1);
}
@@ -98,7 +94,7 @@ areshell(const char *shell)
ptr++;
else
ptr = shell;
progname = __progname;
progname = getprogname();
if (*progname == '-')
progname++;
if (strcmp(ptr, progname) == 0)
@@ -196,8 +192,7 @@ main(int argc, char **argv)
if (setlocale(LC_CTYPE, "") == NULL)
errx(1, "invalid LC_ALL, LC_CTYPE or LANG");
s = nl_langinfo(CODESET);
if (strcasecmp(s, "UTF-8") != 0 &&
strcasecmp(s, "UTF8") != 0)
if (strcasecmp(s, "UTF-8") != 0 && strcasecmp(s, "UTF8") != 0)
errx(1, "need UTF-8 locale (LC_CTYPE) but have %s", s);
}
@@ -226,7 +221,7 @@ main(int argc, char **argv)
flags |= CLIENT_CONTROL;
break;
case 'V':
printf("%s %s\n", __progname, VERSION);
printf("%s %s\n", getprogname(), VERSION);
exit(0);
case 'f':
set_cfg_file(optarg);
@@ -338,5 +333,5 @@ main(int argc, char **argv)
free(label);
/* Pass control to the client. */
exit(client_main(event_init(), argc, argv, flags, shellcmd));
exit(client_main(osdep_event_init(), argc, argv, flags, shellcmd));
}

139
tmux.h
View File

@@ -38,7 +38,6 @@
#include "compat.h"
#include "xmalloc.h"
extern char *__progname;
extern char **environ;
struct client;
@@ -63,14 +62,17 @@ struct tmuxproc;
#define NAME_INTERVAL 500000
/*
* READ_SIZE is the maximum size of data to hold from a pty (the event high
* watermark). READ_BACKOFF is the amount of data waiting to be output to a tty
* before pty reads will be backed off. READ_TIME is how long to back off
* before the next read (in microseconds) if a tty is above READ_BACKOFF.
* Event watermarks. We start with FAST then if we hit full size for HITS reads
* in succession switch to SLOW, and return when we hit EMPTY the same number
* of times.
*/
#define READ_SIZE 1024
#define READ_BACKOFF 512
#define READ_TIME 100
#define READ_FAST_SIZE 4096
#define READ_SLOW_SIZE 128
#define READ_FULL_SIZE (4096 - 16)
#define READ_EMPTY_SIZE 16
#define READ_CHANGE_HITS 3
/* Attribute to make gcc check printf-like arguments. */
#define printflike(a, b) __attribute__ ((format (printf, a, b)))
@@ -538,12 +540,14 @@ enum mode_key_cmd {
MODEKEYCOPY_LEFT,
MODEKEYCOPY_MIDDLELINE,
MODEKEYCOPY_NEXTPAGE,
MODEKEYCOPY_NEXTPARAGRAPH,
MODEKEYCOPY_NEXTSPACE,
MODEKEYCOPY_NEXTSPACEEND,
MODEKEYCOPY_NEXTWORD,
MODEKEYCOPY_NEXTWORDEND,
MODEKEYCOPY_OTHEREND,
MODEKEYCOPY_PREVIOUSPAGE,
MODEKEYCOPY_PREVIOUSPARAGRAPH,
MODEKEYCOPY_PREVIOUSSPACE,
MODEKEYCOPY_PREVIOUSWORD,
MODEKEYCOPY_RECTANGLETOGGLE,
@@ -574,6 +578,7 @@ struct mode_key_data {
/* Binding between a key and a command. */
struct mode_key_binding {
key_code key;
u_int repeat;
int mode;
enum mode_key_cmd cmd;
@@ -633,6 +638,10 @@ enum utf8_state {
UTF8_ERROR
};
/* Colour flags. */
#define COLOUR_FLAG_256 0x01000000
#define COLOUR_FLAG_RGB 0x02000000
/* Grid attributes. */
#define GRID_ATTR_BRIGHT 0x1
#define GRID_ATTR_DIM 0x2
@@ -648,31 +657,18 @@ enum utf8_state {
#define GRID_FLAG_BG256 0x2
#define GRID_FLAG_PADDING 0x4
#define GRID_FLAG_EXTENDED 0x8
#define GRID_FLAG_FGRGB 0x10
#define GRID_FLAG_BGRGB 0x20
#define GRID_FLAG_SELECTED 0x10
/* Grid line flags. */
#define GRID_LINE_WRAPPED 0x1
/* Grid cell RGB colours. */
struct grid_cell_rgb {
u_char r;
u_char g;
u_char b;
};
#define GRID_LINE_EXTENDED 0x2
/* Grid cell data. */
struct grid_cell {
u_char flags;
u_char attr;
union {
u_char fg;
struct grid_cell_rgb fg_rgb;
};
union {
u_char bg;
struct grid_cell_rgb bg_rgb;
};
int fg;
int bg;
struct utf8_data data;
};
@@ -708,6 +704,7 @@ struct grid {
u_int sx;
u_int sy;
u_int hscrolled;
u_int hsize;
u_int hlimit;
@@ -787,30 +784,38 @@ struct screen_sel {
/* Virtual screen. */
struct screen {
char *title;
char *title;
struct grid *grid; /* grid data */
struct grid *grid; /* grid data */
u_int cx; /* cursor x */
u_int cy; /* cursor y */
u_int cx; /* cursor x */
u_int cy; /* cursor y */
u_int cstyle; /* cursor style */
char *ccolour; /* cursor colour string */
u_int cstyle; /* cursor style */
char *ccolour; /* cursor colour string */
u_int rupper; /* scroll region top */
u_int rlower; /* scroll region bottom */
u_int rupper; /* scroll region top */
u_int rlower; /* scroll region bottom */
int mode;
int mode;
bitstr_t *tabs;
bitstr_t *tabs;
struct screen_sel sel;
bitstr_t *dirty;
u_int dirtysize;
struct screen_sel sel;
};
/* Screen write context. */
struct screen_write_ctx {
struct window_pane *wp;
struct screen *s;
struct window_pane *wp;
struct screen *s;
u_int dirty;
u_int cells;
u_int written;
u_int skipped;
};
/* Screen size. */
@@ -830,6 +835,7 @@ struct window_mode {
void (*key)(struct window_pane *, struct client *, struct session *,
key_code, struct mouse_event *);
};
#define WINDOW_MODE_TIMEOUT 180
/* Structures for choose mode. */
struct window_choose_data {
@@ -889,7 +895,11 @@ struct window_pane {
int fd;
struct bufferevent *event;
struct event timer;
struct event resize_timer;
u_int wmark_size;
u_int wmark_hits;
struct input_ctx *ictx;
@@ -902,6 +912,9 @@ struct window_pane {
struct screen *screen;
struct screen base;
struct screen status_screen;
size_t status_size;
/* Saved in alternative screen mode. */
u_int saved_cx;
u_int saved_cy;
@@ -910,6 +923,8 @@ struct window_pane {
const struct window_mode *mode;
void *modedata;
struct event modetimer;
time_t modelast;
TAILQ_ENTRY(window_pane) entry;
RB_ENTRY(window_pane) tree_entry;
@@ -949,10 +964,14 @@ struct window {
#define WINDOW_ZOOMED 0x1000
#define WINDOW_FORCEWIDTH 0x2000
#define WINDOW_FORCEHEIGHT 0x4000
#define WINDOW_STYLECHANGED 0x8000
#define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE)
struct options *options;
struct grid_cell style;
struct grid_cell active_style;
u_int references;
RB_ENTRY(window) entry;
@@ -1207,7 +1226,6 @@ struct tty_ctx {
/* Saved last cell on line. */
struct grid_cell last_cell;
u_int last_width;
};
/* Saved message entry. */
@@ -1275,6 +1293,8 @@ struct client {
struct key_table *keytable;
struct event identify_timer;
void (*identify_callback)(struct client *, struct window_pane *);
void *identify_callback_data;
char *message_string;
struct event message_timer;
@@ -1560,7 +1580,7 @@ extern int cfg_finished;
extern int cfg_references;
extern struct client *cfg_client;
void start_cfg(void);
int load_cfg(const char *, struct cmd_q *, char **);
int load_cfg(const char *, struct cmd_q *, int);
void set_cfg_file(const char *);
void printflike(1, 2) cfg_add_cause(const char *, ...);
void cfg_print_causes(struct cmd_q *);
@@ -1631,7 +1651,7 @@ const struct mode_key_table *mode_key_findtable(const char *);
void mode_key_init_trees(void);
void mode_key_init(struct mode_key_data *, struct mode_key_tree *);
enum mode_key_cmd mode_key_lookup(struct mode_key_data *, key_code,
const char **);
const char **, u_int *);
/* notify.c */
void notify_enable(void);
@@ -1692,6 +1712,7 @@ void environ_put(struct environ *, const char *);
void environ_unset(struct environ *, const char *);
void environ_update(const char *, struct environ *, struct environ *);
void environ_push(struct environ *);
void environ_log(struct environ *, const char *);
/* tty.c */
void tty_create_log(void);
@@ -1730,7 +1751,6 @@ void tty_close(struct tty *);
void tty_free(struct tty *);
void tty_write(void (*)(struct tty *, const struct tty_ctx *),
struct tty_ctx *);
int tty_client_ready(struct client *, struct window_pane *wp);
void tty_cmd_alignmenttest(struct tty *, const struct tty_ctx *);
void tty_cmd_cell(struct tty *, const struct tty_ctx *);
void tty_cmd_clearendofline(struct tty *, const struct tty_ctx *);
@@ -1936,7 +1956,7 @@ void server_destroy_session_group(struct session *);
void server_destroy_session(struct session *);
void server_check_unattached(void);
void server_set_identify(struct client *);
void server_clear_identify(struct client *);
void server_clear_identify(struct client *, struct window_pane *);
int server_set_stdin_callback(struct client *, void (*)(struct client *,
int, void *), void *, char **);
void server_unzoom_window(struct window *);
@@ -1978,10 +1998,10 @@ int xterm_keys_find(const char *, size_t, size_t *, key_code *);
/* colour.c */
int colour_find_rgb(u_char, u_char, u_char);
void colour_set_fg(struct grid_cell *, int);
void colour_set_bg(struct grid_cell *, int);
int colour_join_rgb(u_char, u_char, u_char);
void colour_split_rgb(int, u_char *, u_char *, u_char *);
const char *colour_tostring(int);
int colour_fromstring(const char *);
int colour_fromstring(const char *s);
u_char colour_256to16(u_char);
/* attributes.c */
@@ -1990,6 +2010,7 @@ int attributes_fromstring(const char *);
/* grid.c */
extern const struct grid_cell grid_default_cell;
int grid_cells_equal(const struct grid_cell *, const struct grid_cell *);
struct grid *grid_create(u_int, u_int, u_int);
void grid_destroy(struct grid *);
int grid_compare(struct grid *, struct grid *);
@@ -2034,15 +2055,15 @@ void screen_write_stop(struct screen_write_ctx *);
void screen_write_reset(struct screen_write_ctx *);
size_t printflike(1, 2) screen_write_cstrlen(const char *, ...);
void printflike(4, 5) screen_write_cnputs(struct screen_write_ctx *,
ssize_t, struct grid_cell *, const char *, ...);
ssize_t, const struct grid_cell *, const char *, ...);
size_t printflike(1, 2) screen_write_strlen(const char *, ...);
void printflike(3, 4) screen_write_puts(struct screen_write_ctx *,
struct grid_cell *, const char *, ...);
const struct grid_cell *, const char *, ...);
void printflike(4, 5) screen_write_nputs(struct screen_write_ctx *,
ssize_t, struct grid_cell *, const char *, ...);
ssize_t, const struct grid_cell *, const char *, ...);
void screen_write_vnputs(struct screen_write_ctx *, ssize_t,
struct grid_cell *, const char *, va_list);
void screen_write_putc(struct screen_write_ctx *, struct grid_cell *,
const struct grid_cell *, const char *, va_list);
void screen_write_putc(struct screen_write_ctx *, const struct grid_cell *,
u_char);
void screen_write_copy(struct screen_write_ctx *, struct screen *, u_int,
u_int, u_int, u_int);
@@ -2133,7 +2154,8 @@ int window_has_pane(struct window *, struct window_pane *);
int window_set_active_pane(struct window *, struct window_pane *);
void window_redraw_active_switch(struct window *,
struct window_pane *);
struct window_pane *window_add_pane(struct window *, u_int);
struct window_pane *window_add_pane(struct window *, struct window_pane *,
u_int);
void window_resize(struct window *, u_int, u_int);
int window_zoom(struct window_pane *);
int window_unzoom(struct window *);
@@ -2182,7 +2204,7 @@ u_int layout_count_cells(struct layout_cell *);
struct layout_cell *layout_create_cell(struct layout_cell *);
void layout_free_cell(struct layout_cell *);
void layout_print_cell(struct layout_cell *, const char *, u_int);
void layout_destroy_cell(struct layout_cell *,
void layout_destroy_cell(struct window *, struct layout_cell *,
struct layout_cell **);
void layout_set_size(struct layout_cell *, u_int, u_int, u_int,
u_int);
@@ -2190,9 +2212,8 @@ void layout_make_leaf(struct layout_cell *, struct window_pane *);
void layout_make_node(struct layout_cell *, enum layout_type);
void layout_fix_offsets(struct layout_cell *);
void layout_fix_panes(struct window *, u_int, u_int);
u_int layout_resize_check(struct layout_cell *, enum layout_type);
void layout_resize_adjust(struct layout_cell *, enum layout_type,
int);
void layout_resize_adjust(struct window *, struct layout_cell *,
enum layout_type, int);
void layout_init(struct window *, struct window_pane *);
void layout_free(struct window *);
void layout_resize(struct window *, u_int, u_int);
@@ -2202,7 +2223,7 @@ void layout_resize_pane_to(struct window_pane *, enum layout_type,
u_int);
void layout_assign_pane(struct layout_cell *, struct window_pane *);
struct layout_cell *layout_split_pane(struct window_pane *, enum layout_type,
int, int);
int, int, int);
void layout_close_pane(struct window_pane *);
/* layout-custom.c */
@@ -2225,7 +2246,7 @@ void window_copy_init_from_pane(struct window_pane *, int);
void window_copy_init_for_output(struct window_pane *);
void printflike(2, 3) window_copy_add(struct window_pane *, const char *, ...);
void window_copy_vadd(struct window_pane *, const char *, va_list);
void window_copy_pageup(struct window_pane *);
void window_copy_pageup(struct window_pane *, int);
void window_copy_start_drag(struct client *, struct mouse_event *);
int window_copy_scroll_position(struct window_pane *);

View File

@@ -33,14 +33,17 @@
* into a ternary tree.
*/
void tty_keys_add1(struct tty_key **, const char *, key_code);
void tty_keys_add(struct tty *, const char *, key_code);
void tty_keys_free1(struct tty_key *);
struct tty_key *tty_keys_find1(struct tty_key *, const char *, size_t,
static void tty_keys_add1(struct tty_key **, const char *, key_code);
static void tty_keys_add(struct tty *, const char *, key_code);
static void tty_keys_free1(struct tty_key *);
static struct tty_key *tty_keys_find1(struct tty_key *, const char *, size_t,
size_t *);
struct tty_key *tty_keys_find(struct tty *, const char *, size_t, size_t *);
void tty_keys_callback(int, short, void *);
int tty_keys_mouse(struct tty *, const char *, size_t, size_t *);
static struct tty_key *tty_keys_find(struct tty *, const char *, size_t,
size_t *);
static int tty_keys_next1(struct tty *, const char *, size_t, key_code *,
size_t *, int);
static void tty_keys_callback(int, short, void *);
static int tty_keys_mouse(struct tty *, const char *, size_t, size_t *);
/* Default raw keys. */
struct tty_default_key_raw {
@@ -316,7 +319,7 @@ const struct tty_default_key_code tty_default_code_keys[] = {
};
/* Add key to tree. */
void
static void
tty_keys_add(struct tty *tty, const char *s, key_code key)
{
struct tty_key *tk;
@@ -334,7 +337,7 @@ tty_keys_add(struct tty *tty, const char *s, key_code key)
}
/* Add next node to the tree. */
void
static void
tty_keys_add1(struct tty_key **tkp, const char *s, key_code key)
{
struct tty_key *tk;
@@ -409,7 +412,7 @@ tty_keys_free(struct tty *tty)
}
/* Free a single key. */
void
static void
tty_keys_free1(struct tty_key *tk)
{
if (tk->next != NULL)
@@ -422,7 +425,7 @@ tty_keys_free1(struct tty_key *tk)
}
/* Lookup a key in the tree. */
struct tty_key *
static struct tty_key *
tty_keys_find(struct tty *tty, const char *buf, size_t len, size_t *size)
{
*size = 0;
@@ -430,7 +433,7 @@ tty_keys_find(struct tty *tty, const char *buf, size_t len, size_t *size)
}
/* Find the next node. */
struct tty_key *
static struct tty_key *
tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size)
{
/* If the node is NULL, this is the end of the tree. No match. */
@@ -460,6 +463,58 @@ tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size)
return (tty_keys_find1(tk, buf, len, size));
}
/* Look up part of the next key. */
static int
tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key,
size_t *size, int expired)
{
struct tty_key *tk, *tk1;
struct utf8_data ud;
enum utf8_state more;
u_int i;
wchar_t wc;
log_debug("next key is %zu (%.*s) (expired=%d)", len, (int)len, buf,
expired);
/* Is this a known key? */
tk = tty_keys_find(tty, buf, len, size);
if (tk != NULL && tk->key != KEYC_UNKNOWN) {
tk1 = tk;
do
log_debug("keys in list: %#llx", tk1->key);
while ((tk1 = tk1->next) != NULL);
if (tk->next != NULL && !expired)
return (1);
*key = tk->key;
return (0);
}
/* Is this valid UTF-8? */
more = utf8_open(&ud, (u_char)*buf);
if (more == UTF8_MORE) {
*size = ud.size;
if (len < ud.size) {
if (!expired)
return (1);
return (-1);
}
for (i = 1; i < ud.size; i++)
more = utf8_append(&ud, (u_char)buf[i]);
if (more != UTF8_DONE)
return (-1);
if (utf8_combine(&ud, &wc) != UTF8_DONE)
return (-1);
*key = wc;
log_debug("UTF-8 key %.*s %#llx", (int)ud.size, buf, *key);
return (0);
}
return (-1);
}
/*
* Process at least one key in the buffer and invoke tty->key_callback. Return
* 0 if there are no further keys, or 1 if there could be more in the buffer.
@@ -467,17 +522,12 @@ tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size)
key_code
tty_keys_next(struct tty *tty)
{
struct tty_key *tk;
struct timeval tv;
const char *buf;
size_t len, size;
cc_t bspace;
int delay, expired = 0;
key_code key;
struct utf8_data ud;
enum utf8_state more;
u_int i;
wchar_t wc;
struct timeval tv;
const char *buf;
size_t len, size;
cc_t bspace;
int delay, expired = 0, n;
key_code key;
/* Get key buffer. */
buf = EVBUFFER_DATA(tty->event->input);
@@ -485,7 +535,7 @@ tty_keys_next(struct tty *tty)
if (len == 0)
return (0);
log_debug("keys are %zu (%.*s)", len, (int) len, buf);
log_debug("keys are %zu (%.*s)", len, (int)len, buf);
/* Is this a mouse key press? */
switch (tty_keys_mouse(tty, buf, len, &size)) {
@@ -501,84 +551,49 @@ tty_keys_next(struct tty *tty)
goto partial_key;
}
/* Look for matching key string and return if found. */
tk = tty_keys_find(tty, buf, len, &size);
if (tk != NULL) {
if (tk->next != NULL)
goto partial_key;
key = tk->key;
goto complete_key;
}
/* Try to parse a key with an xterm-style modifier. */
switch (xterm_keys_find(buf, len, &size, &key)) {
case 0: /* found */
goto complete_key;
case -1: /* not found */
break;
case 1:
goto partial_key;
}
first_key:
/* Is this a meta key? */
if (len >= 2 && buf[0] == '\033') {
if (buf[1] != '\033') {
key = buf[1] | KEYC_ESCAPE;
size = 2;
/* Handle keys starting with escape. */
if (*buf == '\033') {
/* Look for a key without the escape. */
n = tty_keys_next1(tty, buf + 1, len - 1, &key, &size, expired);
if (n == 0) { /* found */
key |= KEYC_ESCAPE;
size++;
goto complete_key;
}
tk = tty_keys_find(tty, buf + 1, len - 1, &size);
if (tk != NULL && (!expired || tk->next == NULL)) {
size++; /* include escape */
if (tk->next != NULL)
goto partial_key;
key = tk->key;
if (key != KEYC_UNKNOWN)
key |= KEYC_ESCAPE;
goto complete_key;
}
}
/* Is this valid UTF-8? */
if ((more = utf8_open(&ud, (u_char)*buf) == UTF8_MORE)) {
size = ud.size;
if (len < size) {
if (expired)
goto discard_key;
if (n == 1) /* partial */
goto partial_key;
}
for (i = 1; i < size; i++)
more = utf8_append(&ud, (u_char)buf[i]);
if (more != UTF8_DONE)
goto discard_key;
if (utf8_combine(&ud, &wc) != UTF8_DONE)
goto discard_key;
key = wc;
log_debug("UTF-8 key %.*s %#llx", (int)size, buf, key);
goto complete_key;
}
/* No key found, take first. */
key = (u_char)*buf;
size = 1;
/* Try to lookup key. */
n = tty_keys_next1(tty, buf, len, &key, &size, expired);
if (n == 0) /* found */
goto complete_key;
if (n == 1)
goto partial_key;
/* Is this an an xterm(1) key? */
n = xterm_keys_find(buf, len, &size, &key);
if (n == 0)
goto complete_key;
if (n == 1 && !expired)
goto partial_key;
/*
* Check for backspace key using termios VERASE - the terminfo
* kbs entry is extremely unreliable, so cannot be safely
* used. termios should have a better idea.
* At this point, we know the key is not partial (with or without
* escape). So pass it through even if the timer has not expired.
*/
bspace = tty->tio.c_cc[VERASE];
if (bspace != _POSIX_VDISABLE && key == bspace)
key = KEYC_BSPACE;
if (*buf == '\033' && len >= 2) {
key = (u_char)buf[1] | KEYC_ESCAPE;
size = 2;
} else {
key = (u_char)buf[0];
size = 1;
}
goto complete_key;
partial_key:
log_debug("partial key %.*s", (int) len, buf);
log_debug("partial key %.*s", (int)len, buf);
/* If timer is going, check for expiration. */
if (tty->flags & TTY_TIMER) {
@@ -607,6 +622,15 @@ partial_key:
complete_key:
log_debug("complete key %.*s %#llx", (int)size, buf, key);
/*
* Check for backspace key using termios VERASE - the terminfo
* kbs entry is extremely unreliable, so cannot be safely
* used. termios should have a better idea.
*/
bspace = tty->tio.c_cc[VERASE];
if (bspace != _POSIX_VDISABLE && (key & KEYC_MASK_KEY) == bspace)
key = (key & KEYC_MASK_MOD) | KEYC_BSPACE;
/* Remove data from buffer. */
evbuffer_drain(tty->event->input, size);
@@ -640,7 +664,7 @@ discard_key:
}
/* Key timer callback. */
void
static void
tty_keys_callback(__unused int fd, __unused short events, void *data)
{
struct tty *tty = data;
@@ -655,7 +679,7 @@ tty_keys_callback(__unused int fd, __unused short events, void *data)
* Handle mouse key input. Returns 0 for success, -1 for failure, 1 for partial
* (probably a mouse sequence but need more data).
*/
int
static int
tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
{
struct mouse_event *m = &tty->mouse;

350
tty.c
View File

@@ -36,15 +36,10 @@ static int tty_log_fd = -1;
void tty_read_callback(struct bufferevent *, void *);
void tty_error_callback(struct bufferevent *, short, void *);
static int tty_same_fg(const struct grid_cell *, const struct grid_cell *);
static int tty_same_bg(const struct grid_cell *, const struct grid_cell *);
static int tty_same_colours(const struct grid_cell *, const struct grid_cell *);
static int tty_is_fg(const struct grid_cell *, int);
static int tty_is_bg(const struct grid_cell *, int);
static int tty_client_ready(struct client *, struct window_pane *);
void tty_set_italics(struct tty *);
int tty_try_256(struct tty *, u_char, const char *);
int tty_try_rgb(struct tty *, const struct grid_cell_rgb *, const char *);
int tty_try_colour(struct tty *, int, const char *);
void tty_colours(struct tty *, const struct grid_cell *);
void tty_check_fg(struct tty *, struct grid_cell *);
@@ -68,74 +63,6 @@ void tty_default_colours(struct grid_cell *, const struct window_pane *);
#define tty_pane_full_width(tty, ctx) \
((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx)
static int
tty_same_fg(const struct grid_cell *gc1, const struct grid_cell *gc2)
{
int flags1, flags2;
flags1 = (gc1->flags & (GRID_FLAG_FG256|GRID_FLAG_FGRGB));
flags2 = (gc2->flags & (GRID_FLAG_FG256|GRID_FLAG_FGRGB));
if (flags1 != flags2)
return (0);
if (flags1 & GRID_FLAG_FGRGB) {
if (gc1->fg_rgb.r != gc2->fg_rgb.r)
return (0);
if (gc1->fg_rgb.g != gc2->fg_rgb.g)
return (0);
if (gc1->fg_rgb.b != gc2->fg_rgb.b)
return (0);
return (1);
}
return (gc1->fg == gc2->fg);
}
static int
tty_same_bg(const struct grid_cell *gc1, const struct grid_cell *gc2)
{
int flags1, flags2;
flags1 = (gc1->flags & (GRID_FLAG_BG256|GRID_FLAG_BGRGB));
flags2 = (gc2->flags & (GRID_FLAG_BG256|GRID_FLAG_BGRGB));
if (flags1 != flags2)
return (0);
if (flags1 & GRID_FLAG_BGRGB) {
if (gc1->bg_rgb.r != gc2->bg_rgb.r)
return (0);
if (gc1->bg_rgb.g != gc2->bg_rgb.g)
return (0);
if (gc1->bg_rgb.b != gc2->bg_rgb.b)
return (0);
return (1);
}
return (gc1->bg == gc2->bg);
}
static int
tty_same_colours(const struct grid_cell *gc1, const struct grid_cell *gc2)
{
return (tty_same_fg(gc1, gc2) && tty_same_bg(gc1, gc2));
}
static int
tty_is_fg(const struct grid_cell *gc, int c)
{
if (gc->flags & (GRID_FLAG_FG256|GRID_FLAG_FGRGB))
return (0);
return (gc->fg == c);
}
static int
tty_is_bg(const struct grid_cell *gc, int c)
{
if (gc->flags & (GRID_FLAG_BG256|GRID_FLAG_BGRGB))
return (0);
return (gc->bg == c);
}
void
tty_create_log(void)
{
@@ -674,9 +601,10 @@ tty_fake_bce(const struct tty *tty, const struct window_pane *wp)
struct grid_cell gc;
memcpy(&gc, &grid_default_cell, sizeof gc);
tty_default_colours(&gc, wp);
if (wp != NULL)
tty_default_colours(&gc, wp);
if (gc.bg == 8 && !(gc.flags & GRID_FLAG_BG256))
if (gc.bg == 8)
return (0);
return (!tty_term_flag(tty->term, TTYC_BCE));
}
@@ -691,7 +619,7 @@ tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx)
{
struct window_pane *wp = ctx->wp;
struct screen *s = wp->screen;
u_int i;
u_int i;
/*
* If region is large, schedule a window redraw. In most cases this is
@@ -751,11 +679,6 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
for (i = 0; i < sx; i++) {
grid_view_get_cell(s->grid, i, py, &gc);
if (screen_check_selection(s, i, py)) {
gc.flags &= ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
gc.flags |= s->sel.cell.flags &
(GRID_FLAG_FG256|GRID_FLAG_BG256);
}
tty_cell(tty, &gc, wp);
}
@@ -776,7 +699,7 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
tty_update_mode(tty, tty->mode, s);
}
int
static int
tty_client_ready(struct client *c, struct window_pane *wp)
{
if (c->session == NULL || c->tty.term == NULL)
@@ -1022,7 +945,7 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx)
{
struct window_pane *wp = ctx->wp;
struct screen *s = wp->screen;
u_int i, j;
u_int i, j;
tty_attributes(tty, &grid_default_cell, wp);
@@ -1056,7 +979,7 @@ tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx)
{
struct window_pane *wp = ctx->wp;
struct screen *s = wp->screen;
u_int i, j;
u_int i, j;
tty_attributes(tty, &grid_default_cell, wp);
@@ -1084,7 +1007,7 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx)
{
struct window_pane *wp = ctx->wp;
struct screen *s = wp->screen;
u_int i, j;
u_int i, j;
tty_attributes(tty, &grid_default_cell, wp);
@@ -1131,10 +1054,10 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
{
struct window_pane *wp = ctx->wp;
struct screen *s = wp->screen;
u_int cx;
u_int width;
u_int cx, width;
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
if (ctx->ocy == ctx->orlower)
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
/* Is the cursor in the very last position? */
width = ctx->cell->data.width;
@@ -1252,7 +1175,7 @@ tty_reset(struct tty *tty)
{
struct grid_cell *gc = &tty->cell;
if (memcmp(gc, &grid_default_cell, sizeof *gc) == 0)
if (grid_cells_equal(gc, &grid_default_cell))
return;
if ((gc->attr & GRID_ATTR_CHARSET) && tty_use_acs(tty))
@@ -1343,7 +1266,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy)
*/
/* To left edge. */
if (cx == 0) {
if (cx == 0) {
tty_putc(tty, '\r');
goto out;
}
@@ -1371,6 +1294,11 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy)
tty_putcode1(tty, TTYC_HPA, cx);
goto out;
} else if (change > 0 && tty_term_has(term, TTYC_CUB)) {
if (change == 2 && tty_term_has(term, TTYC_CUB1)) {
tty_putcode(tty, TTYC_CUB1);
tty_putcode(tty, TTYC_CUB1);
goto out;
}
tty_putcode1(tty, TTYC_CUB, change);
goto out;
} else if (change < 0 && tty_term_has(term, TTYC_CUF)) {
@@ -1436,7 +1364,8 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc,
u_char changed;
memcpy(&gc2, gc, sizeof gc2);
tty_default_colours(&gc2, wp);
if (wp != NULL)
tty_default_colours(&gc2, wp);
/*
* If no setab, try to use the reverse attribute as a best-effort for a
@@ -1498,10 +1427,10 @@ void
tty_colours(struct tty *tty, const struct grid_cell *gc)
{
struct grid_cell *tc = &tty->cell;
int have_ax, fg_default, bg_default;
int have_ax;
/* No changes? Nothing is necessary. */
if (tty_same_colours(gc, tc))
if (gc->fg == tc->fg && gc->bg == tc->bg)
return;
/*
@@ -1510,9 +1439,7 @@ tty_colours(struct tty *tty, const struct grid_cell *gc)
* case if only one is default need to fall onward to set the other
* colour.
*/
fg_default = tty_is_fg(gc, 8);
bg_default = tty_is_bg(gc, 8);
if (fg_default || bg_default) {
if (gc->fg == 8 || gc->bg == 8) {
/*
* If don't have AX but do have op, send sgr0 (op can't
* actually be used because it is sometimes the same as sgr0
@@ -1524,58 +1451,54 @@ tty_colours(struct tty *tty, const struct grid_cell *gc)
if (!have_ax && tty_term_has(tty->term, TTYC_OP))
tty_reset(tty);
else {
if (fg_default && !tty_is_fg(tc, 8)) {
if (gc->fg == 8 && tc->fg != 8) {
if (have_ax)
tty_puts(tty, "\033[39m");
else if (!tty_is_fg(tc, 7))
else if (tc->fg != 7)
tty_putcode1(tty, TTYC_SETAF, 7);
tc->fg = 8;
tc->flags &= ~(GRID_FLAG_FG256|GRID_FLAG_FGRGB);
}
if (bg_default && !tty_is_bg(tc, 8)) {
if (gc->bg == 8 && tc->bg != 8) {
if (have_ax)
tty_puts(tty, "\033[49m");
else if (!tty_is_bg(tc, 0))
else if (tc->bg != 0)
tty_putcode1(tty, TTYC_SETAB, 0);
tc->bg = 8;
tc->flags &= ~(GRID_FLAG_BG256|GRID_FLAG_BGRGB);
}
}
}
/* Set the foreground colour. */
if (!fg_default && !tty_same_fg(gc, tc))
if (gc->fg != 8 && gc->fg != tc->fg)
tty_colours_fg(tty, gc);
/*
* Set the background colour. This must come after the foreground as
* tty_colour_fg() can call tty_reset().
*/
if (!bg_default && !tty_same_bg(gc, tc))
if (gc->bg != 8 && gc->bg != tc->bg)
tty_colours_bg(tty, gc);
}
void
tty_check_fg(struct tty *tty, struct grid_cell *gc)
{
struct grid_cell_rgb *rgb = &gc->fg_rgb;
u_int colours;
u_char r, g, b;
u_int colours;
/* Is this a 24-bit colour? */
if (gc->flags & GRID_FLAG_FGRGB) {
if (gc->fg & COLOUR_FLAG_RGB) {
/* Not a 24-bit terminal? Translate to 256-colour palette. */
if (!tty_term_flag(tty->term, TTYC_TC)) {
gc->flags &= ~GRID_FLAG_FGRGB;
gc->flags |= GRID_FLAG_FG256;
gc->fg = colour_find_rgb(rgb->r, rgb->g, rgb->b);
}
else
colour_split_rgb(gc->fg, &r, &g, &b);
gc->fg = colour_find_rgb(r, g, b);
} else
return;
}
colours = tty_term_number(tty->term, TTYC_COLORS);
/* Is this a 256-colour colour? */
if (gc->flags & GRID_FLAG_FG256) {
if (gc->fg & COLOUR_FLAG_256) {
/* And not a 256 colour mode? */
if (!(tty->term->flags & TERM_256COLOURS) &&
!(tty->term_flags & TERM_256COLOURS)) {
@@ -1588,7 +1511,6 @@ tty_check_fg(struct tty *tty, struct grid_cell *gc)
gc->attr |= GRID_ATTR_BRIGHT;
} else
gc->attr &= ~GRID_ATTR_BRIGHT;
gc->flags &= ~GRID_FLAG_FG256;
}
return;
}
@@ -1603,24 +1525,22 @@ tty_check_fg(struct tty *tty, struct grid_cell *gc)
void
tty_check_bg(struct tty *tty, struct grid_cell *gc)
{
struct grid_cell_rgb *rgb = &gc->bg_rgb;
u_int colours;
u_char r, g, b;
u_int colours;
/* Is this a 24-bit colour? */
if (gc->flags & GRID_FLAG_BGRGB) {
if (gc->bg & COLOUR_FLAG_RGB) {
/* Not a 24-bit terminal? Translate to 256-colour palette. */
if (!tty_term_flag(tty->term, TTYC_TC)) {
gc->flags &= ~GRID_FLAG_BGRGB;
gc->flags |= GRID_FLAG_BG256;
gc->bg = colour_find_rgb(rgb->r, rgb->g, rgb->b);
}
else
colour_split_rgb(gc->bg, &r, &g, &b);
gc->bg = colour_find_rgb(r, g, b);
} else
return;
}
colours = tty_term_number(tty->term, TTYC_COLORS);
/* Is this a 256-colour colour? */
if (gc->flags & GRID_FLAG_BG256) {
if (gc->bg & COLOUR_FLAG_256) {
/*
* And not a 256 colour mode? Translate to 16-colour
* palette. Bold background doesn't exist portably, so just
@@ -1634,7 +1554,6 @@ tty_check_bg(struct tty *tty, struct grid_cell *gc)
if (colours >= 16)
gc->fg += 90;
}
gc->flags &= ~GRID_FLAG_BG256;
}
return;
}
@@ -1648,137 +1567,111 @@ void
tty_colours_fg(struct tty *tty, const struct grid_cell *gc)
{
struct grid_cell *tc = &tty->cell;
u_char fg = gc->fg;
char s[32];
tc->flags &= ~(GRID_FLAG_FG256|GRID_FLAG_FGRGB);
/* Is this a 24-bit colour? */
if (gc->flags & GRID_FLAG_FGRGB) {
if (tty_try_rgb(tty, &gc->fg_rgb, "38") == 0)
goto save_fg;
/* Should not get here, already converted in tty_check_fg. */
return;
}
/* Is this a 256-colour colour? */
if (gc->flags & GRID_FLAG_FG256) {
if (tty_try_256(tty, fg, "38") == 0)
/* Is this a 24-bit or 256-colour colour? */
if (gc->fg & COLOUR_FLAG_RGB ||
gc->fg & COLOUR_FLAG_256) {
if (tty_try_colour(tty, gc->fg, "38") == 0)
goto save_fg;
/* Should not get here, already converted in tty_check_fg. */
return;
}
/* Is this an aixterm bright colour? */
if (fg >= 90 && fg <= 97) {
xsnprintf(s, sizeof s, "\033[%dm", fg);
if (gc->fg >= 90 && gc->fg <= 97) {
xsnprintf(s, sizeof s, "\033[%dm", gc->fg);
tty_puts(tty, s);
goto save_fg;
}
/* Otherwise set the foreground colour. */
tty_putcode1(tty, TTYC_SETAF, fg);
tty_putcode1(tty, TTYC_SETAF, gc->fg);
save_fg:
/* Save the new values in the terminal current cell. */
if (gc->flags & GRID_FLAG_FGRGB)
memcpy(&tc->fg_rgb, &gc->fg_rgb, sizeof tc->fg_rgb);
else
tc->fg = fg;
tc->flags &= ~(GRID_FLAG_FGRGB|GRID_FLAG_FG256);
tc->flags |= (gc->flags & (GRID_FLAG_FG256|GRID_FLAG_FGRGB));
tc->fg = gc->fg;
}
void
tty_colours_bg(struct tty *tty, const struct grid_cell *gc)
{
struct grid_cell *tc = &tty->cell;
u_char bg = gc->bg;
char s[32];
/* Is this a 24-bit colour? */
if (gc->flags & GRID_FLAG_BGRGB) {
if (tty_try_rgb(tty, &gc->bg_rgb, "48") == 0)
goto save_bg;
/* Should not get here, already converted in tty_check_bg. */
return;
}
/* Is this a 256-colour colour? */
if (gc->flags & GRID_FLAG_BG256) {
if (tty_try_256(tty, bg, "48") == 0)
/* Is this a 24-bit or 256-colour colour? */
if (gc->bg & COLOUR_FLAG_RGB ||
gc->bg & COLOUR_FLAG_256) {
if (tty_try_colour(tty, gc->bg, "48") == 0)
goto save_bg;
/* Should not get here, already converted in tty_check_bg. */
return;
}
/* Is this an aixterm bright colour? */
if (bg >= 90 && bg <= 97) {
xsnprintf(s, sizeof s, "\033[%dm", bg + 10);
if (gc->bg >= 90 && gc->bg <= 97) {
xsnprintf(s, sizeof s, "\033[%dm", gc->bg + 10);
tty_puts(tty, s);
goto save_bg;
}
/* Otherwise set the background colour. */
tty_putcode1(tty, TTYC_SETAB, bg);
tty_putcode1(tty, TTYC_SETAB, gc->bg);
save_bg:
/* Save the new values in the terminal current cell. */
if (gc->flags & GRID_FLAG_BGRGB)
memcpy(&tc->bg_rgb, &gc->bg_rgb, sizeof tc->bg_rgb);
else
tc->bg = bg;
tc->flags &= ~(GRID_FLAG_BGRGB|GRID_FLAG_BG256);
tc->flags |= (gc->flags & (GRID_FLAG_BG256|GRID_FLAG_BGRGB));
tc->bg = gc->bg;
}
int
tty_try_256(struct tty *tty, u_char colour, const char *type)
tty_try_colour(struct tty *tty, int colour, const char *type)
{
u_char r, g, b;
char s[32];
/*
* If the user has specified -2 to the client, setaf and setab may not
* work (or they may not want to use them), so send the usual sequence.
*/
if (tty->term_flags & TERM_256COLOURS)
goto fallback;
if (colour & COLOUR_FLAG_256) {
/*
* If the user has specified -2 to the client, setaf and setab
* may not work (or they may not want to use them), so send the
* usual sequence.
*/
if (tty->term_flags & TERM_256COLOURS)
goto fallback_256;
/*
* If the terminfo entry has 256 colours and setaf and setab exist,
* assume that they work correctly.
*/
if (tty->term->flags & TERM_256COLOURS) {
if (*type == '3') {
if (!tty_term_has(tty->term, TTYC_SETAF))
goto fallback;
tty_putcode1(tty, TTYC_SETAF, colour);
} else {
if (!tty_term_has(tty->term, TTYC_SETAB))
goto fallback;
tty_putcode1(tty, TTYC_SETAB, colour);
/*
* If the terminfo entry has 256 colours and setaf and setab
* exist, assume that they work correctly.
*/
if (tty->term->flags & TERM_256COLOURS) {
if (*type == '3') {
if (!tty_term_has(tty->term, TTYC_SETAF))
goto fallback_256;
tty_putcode1(tty, TTYC_SETAF, colour & 0xff);
} else {
if (!tty_term_has(tty->term, TTYC_SETAB))
goto fallback_256;
tty_putcode1(tty, TTYC_SETAB, colour & 0xff);
}
return (0);
}
goto fallback_256;
}
if (colour & COLOUR_FLAG_RGB) {
if (!tty_term_flag(tty->term, TTYC_TC))
return (-1);
colour_split_rgb(colour & 0xffffff, &r, &g, &b);
xsnprintf(s, sizeof s, "\033[%s;2;%hhu;%hhu;%hhum", type,
r, g, b);
tty_puts(tty, s);
return (0);
}
return (-1);
fallback:
xsnprintf(s, sizeof s, "\033[%s;5;%hhum", type, colour);
tty_puts(tty, s);
return (0);
}
int
tty_try_rgb(struct tty *tty, const struct grid_cell_rgb *rgb, const char *type)
{
char s[32];
if (!tty_term_flag(tty->term, TTYC_TC))
return (-1);
xsnprintf(s, sizeof s, "\033[%s;2;%hhu;%hhu;%hhum", type, rgb->r,
rgb->g, rgb->b);
fallback_256:
xsnprintf(s, sizeof s, "\033[%s;5;%dm", type, colour & 0xff);
tty_puts(tty, s);
return (0);
}
@@ -1786,40 +1679,37 @@ tty_try_rgb(struct tty *tty, const struct grid_cell_rgb *rgb, const char *type)
void
tty_default_colours(struct grid_cell *gc, const struct window_pane *wp)
{
const struct grid_cell *agc, *pgc, *wgc;
if (wp == NULL)
return;
struct window *w = wp->window;
struct options *oo = w->options;
const struct grid_cell *agc, *pgc, *wgc;
if (w->flags & WINDOW_STYLECHANGED) {
w->flags &= ~WINDOW_STYLECHANGED;
agc = options_get_style(oo, "window-active-style");
memcpy(&w->active_style, agc, sizeof w->active_style);
wgc = options_get_style(oo, "window-style");
memcpy(&w->style, wgc, sizeof w->style);
} else {
agc = &w->active_style;
wgc = &w->style;
}
pgc = &wp->colgc;
agc = options_get_style(wp->window->options, "window-active-style");
wgc = options_get_style(wp->window->options, "window-style");
if (gc->fg == 8 && !(gc->flags & GRID_FLAG_FG256)) {
if (pgc->fg != 8 || (pgc->flags & GRID_FLAG_FG256)) {
if (gc->fg == 8) {
if (pgc->fg != 8)
gc->fg = pgc->fg;
gc->flags |= (pgc->flags & GRID_FLAG_FG256);
} else if (wp == wp->window->active &&
(agc->fg != 8 || (agc->flags & GRID_FLAG_FG256))) {
else if (wp == w->active && agc->fg != 8)
gc->fg = agc->fg;
gc->flags |= (agc->flags & GRID_FLAG_FG256);
} else {
else
gc->fg = wgc->fg;
gc->flags |= (wgc->flags & GRID_FLAG_FG256);
}
}
if (gc->bg == 8 && !(gc->flags & GRID_FLAG_BG256)) {
if (pgc->bg != 8 || (pgc->flags & GRID_FLAG_BG256)) {
if (gc->bg == 8) {
if (pgc->bg != 8)
gc->bg = pgc->bg;
gc->flags |= (pgc->flags & GRID_FLAG_BG256);
} else if (wp == wp->window->active &&
(agc->bg != 8 || (agc->flags & GRID_FLAG_BG256))) {
else if (wp == w->active && agc->bg != 8)
gc->bg = agc->bg;
gc->flags |= (agc->flags & GRID_FLAG_BG256);
} else {
else
gc->bg = wgc->bg;
gc->flags |= (wgc->flags & GRID_FLAG_BG256);
}
}
}

43
utf8.c
View File

@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
@@ -30,16 +31,10 @@ static int utf8_width(wchar_t);
void
utf8_set(struct utf8_data *ud, u_char ch)
{
u_int i;
static const struct utf8_data empty = { { 0 }, 1, 1, 1 };
memcpy(ud, &empty, sizeof *ud);
*ud->data = ch;
ud->have = 1;
ud->size = 1;
ud->width = 1;
for (i = ud->size; i < sizeof ud->data; i++)
ud->data[i] = '\0';
}
/* Copy UTF-8 character. */
@@ -114,9 +109,29 @@ utf8_width(wchar_t wc)
{
int width;
#ifdef HAVE_UTF8PROC
width = utf8proc_wcwidth(wc);
#else
width = wcwidth(wc);
if (width < 0 || width > 0xff)
#endif
if (width < 0 || width > 0xff) {
log_debug("Unicode %04x, wcwidth() %d", wc, width);
#ifndef __OpenBSD__
/*
* Many platforms (particularly and inevitably OS X) have no
* width for relatively common characters (wcwidth() returns
* -1); assume width 1 in this case. This will be wrong for
* genuinely nonprintable characters, but they should be
* rare. We may pass through stuff that ideally we would block,
* but this is no worse than sending the same to the terminal
* without tmux.
*/
if (width < 0)
return (1);
#endif
return (-1);
}
return (width);
}
@@ -124,8 +139,14 @@ utf8_width(wchar_t wc)
enum utf8_state
utf8_combine(const struct utf8_data *ud, wchar_t *wc)
{
#ifdef HAVE_UTF8PROC
switch (utf8proc_mbtowc(wc, ud->data, ud->size)) {
#else
switch (mbtowc(wc, ud->data, ud->size)) {
#endif
case -1:
log_debug("UTF-8 %.*s, mbtowc() %d", (int)ud->size, ud->data,
errno);
mbtowc(NULL, NULL, MB_CUR_MAX);
return (UTF8_ERROR);
case 0:
@@ -142,7 +163,11 @@ utf8_split(wchar_t wc, struct utf8_data *ud)
char s[MB_LEN_MAX];
int slen;
#ifdef HAVE_UTF8PROC
slen = utf8proc_wctomb(s, wc);
#else
slen = wctomb(s, wc);
#endif
if (slen <= 0 || slen > (int)sizeof ud->data)
return (UTF8_ERROR);

View File

@@ -22,7 +22,6 @@
#include <stdlib.h>
#include <string.h>
#include "array.h"
#include "tmux.h"
struct screen *window_choose_init(struct window_pane *);
@@ -72,8 +71,11 @@ struct window_choose_mode_data {
struct mode_key_data mdata;
ARRAY_DECL(, struct window_choose_mode_item) list;
ARRAY_DECL(, struct window_choose_mode_item) old_list;
struct window_choose_mode_item *list;
u_int list_size;
struct window_choose_mode_item *old_list;
u_int old_list_size;
int width;
u_int top;
u_int selected;
@@ -96,17 +98,18 @@ window_choose_add(struct window_pane *wp, struct window_choose_data *wcd)
{
struct window_choose_mode_data *data = wp->modedata;
struct window_choose_mode_item *item;
char tmp[10];
char tmp[11];
ARRAY_EXPAND(&data->list, 1);
item = &ARRAY_LAST(&data->list);
data->list = xreallocarray(data->list, data->list_size + 1,
sizeof *data->list);
item = &data->list[data->list_size++];
item->name = format_expand(wcd->ft, wcd->ft_template);
item->wcd = wcd;
item->pos = ARRAY_LENGTH(&data->list) - 1;
item->pos = data->list_size - 1;
item->state = 0;
data->width = xsnprintf(tmp, sizeof tmp , "%d", item->pos);
data->width = xsnprintf(tmp, sizeof tmp, "%d", item->pos);
}
void
@@ -136,12 +139,18 @@ window_choose_ready(struct window_pane *wp, u_int cur,
void (*callbackfn)(struct window_choose_data *))
{
struct window_choose_mode_data *data = wp->modedata;
u_int size;
data->callbackfn = callbackfn;
if (data->callbackfn == NULL)
data->callbackfn = window_choose_default_callback;
ARRAY_CONCAT(&data->old_list, &data->list);
size = data->old_list_size;
data->old_list_size += data->list_size;
data->old_list = xreallocarray(data->old_list, data->old_list_size,
sizeof *data->old_list);
memcpy(data->old_list + size, data->list, data->list_size *
sizeof *data->list);
window_choose_set_current(wp, cur);
window_choose_collapse_all(wp);
@@ -154,15 +163,19 @@ window_choose_init(struct window_pane *wp)
struct screen *s;
int keys;
wp->modedata = data = xmalloc(sizeof *data);
wp->modedata = data = xcalloc(1, sizeof *data);
data->callbackfn = NULL;
data->input_type = WINDOW_CHOOSE_NORMAL;
data->input_str = xstrdup("");
data->input_prompt = NULL;
ARRAY_INIT(&data->list);
ARRAY_INIT(&data->old_list);
data->list = NULL;
data->list_size = 0;
data->old_list = NULL;
data->old_list_size = 0;
data->top = 0;
s = &data->screen;
@@ -274,13 +287,14 @@ window_choose_free1(struct window_choose_mode_data *data)
if (data == NULL)
return;
for (i = 0; i < ARRAY_LENGTH(&data->old_list); i++) {
item = &ARRAY_ITEM(&data->old_list, i);
for (i = 0; i < data->old_list_size; i++) {
item = &data->old_list[i];
window_choose_data_free(item->wcd);
free(item->name);
}
ARRAY_FREE(&data->list);
ARRAY_FREE(&data->old_list);
free(data->list);
free(data->old_list);
free(data->input_str);
screen_free(&data->screen);
@@ -334,14 +348,11 @@ void
window_choose_collapse(struct window_pane *wp, struct session *s, u_int pos)
{
struct window_choose_mode_data *data = wp->modedata;
struct window_choose_mode_item *item, *chosen;
struct window_choose_mode_item *item, *chosen, *copy = NULL;
struct window_choose_data *wcd;
u_int i;
u_int i, copy_size = 0;
ARRAY_DECL(, struct window_choose_mode_item) list_copy;
ARRAY_INIT(&list_copy);
chosen = &ARRAY_ITEM(&data->list, pos);
chosen = &data->list[pos];
chosen->state &= ~TREE_EXPANDED;
/*
@@ -349,15 +360,19 @@ window_choose_collapse(struct window_pane *wp, struct session *s, u_int pos)
* assign the actual result we want to render and copy the new one over
* the top of it.
*/
for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
item = &ARRAY_ITEM(&data->list, i);
for (i = 0; i < data->list_size; i++) {
item = &data->list[i];
wcd = item->wcd;
if (s == wcd->tree_session) {
/* We only show the session when collapsed. */
if (wcd->type & TREE_SESSION) {
item->state &= ~TREE_EXPANDED;
ARRAY_ADD(&list_copy, *item);
copy = xreallocarray(copy, copy_size + 1,
sizeof *copy);
memcpy(&copy[copy_size], item, sizeof *copy);
copy_size++;
/*
* Update the selection to this session item so
@@ -366,14 +381,17 @@ window_choose_collapse(struct window_pane *wp, struct session *s, u_int pos)
*/
data->selected = i;
}
} else
ARRAY_ADD(&list_copy, ARRAY_ITEM(&data->list, i));
} else {
copy = xreallocarray(copy, copy_size + 1, sizeof *copy);
memcpy(&copy[copy_size], item, sizeof *copy);
copy_size++;
}
}
if (!ARRAY_EMPTY(&list_copy)) {
ARRAY_FREE(&data->list);
ARRAY_CONCAT(&data->list, &list_copy);
ARRAY_FREE(&list_copy);
if (copy_size != 0) {
free(data->list);
data->list = copy;
data->list_size = copy_size;
}
}
@@ -386,14 +404,14 @@ window_choose_collapse_all(struct window_pane *wp)
struct session *s, *chosen;
u_int i;
chosen = ARRAY_ITEM(&data->list, data->selected).wcd->start_session;
chosen = data->list[data->selected].wcd->start_session;
RB_FOREACH(s, sessions, &sessions)
window_choose_collapse(wp, s, data->selected);
/* Reset the selection back to the starting session. */
for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
item = &ARRAY_ITEM(&data->list, i);
for (i = 0; i < data->list_size; i++) {
item = &data->list[i];
if (chosen != item->wcd->tree_session)
continue;
@@ -414,8 +432,8 @@ window_choose_expand_all(struct window_pane *wp)
u_int i;
RB_FOREACH(s, sessions, &sessions) {
for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
item = &ARRAY_ITEM(&data->list, i);
for (i = 0; i < data->list_size; i++) {
item = &data->list[i];
if (s != item->wcd->tree_session)
continue;
@@ -436,8 +454,8 @@ window_choose_expand(struct window_pane *wp, struct session *s, u_int pos)
struct window_choose_data *wcd;
u_int i, items;
chosen = &ARRAY_ITEM(&data->list, pos);
items = ARRAY_LENGTH(&data->old_list) - 1;
chosen = &data->list[pos];
items = data->old_list_size - 1;
/* It's not possible to expand anything other than sessions. */
if (!(chosen->wcd->type & TREE_SESSION))
@@ -456,7 +474,7 @@ window_choose_expand(struct window_pane *wp, struct session *s, u_int pos)
* to expand.
*/
for (i = items; i > 0; i--) {
item = &ARRAY_ITEM(&data->old_list, i);
item = &data->old_list[i];
item->state |= TREE_EXPANDED;
wcd = item->wcd;
@@ -473,16 +491,27 @@ window_choose_expand(struct window_pane *wp, struct session *s, u_int pos)
* entries in order *AFTER* the selected
* session.
*/
if (pos < i ) {
ARRAY_INSERT(&data->list,
pos + 1,
ARRAY_ITEM(&data->old_list,
i));
if (pos < i) {
data->list = xreallocarray(data->list,
data->list_size + 1,
sizeof *data->list);
memmove(&data->list[pos + 2],
&data->list[pos + 1],
(data->list_size - (pos + 1)) *
sizeof *data->list);
memcpy(&data->list[pos + 1],
&data->old_list[i],
sizeof *data->list);
data->list_size++;
} else {
/* Ran out of room, add to the end. */
ARRAY_ADD(&data->list,
ARRAY_ITEM(&data->old_list,
i));
data->list = xreallocarray(data->list,
data->list_size + 1,
sizeof *data->list);
memcpy(&data->list[data->list_size],
&data->old_list[i],
sizeof *data->list);
data->list_size++;
}
}
}
@@ -497,15 +526,15 @@ window_choose_get_item(struct window_pane *wp, key_code key,
u_int x, y, idx;
if (!KEYC_IS_MOUSE(key))
return (&ARRAY_ITEM(&data->list, data->selected));
return (&data->list[data->selected]);
if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
return (NULL);
idx = data->top + y;
if (idx >= ARRAY_LENGTH(&data->list))
if (idx >= data->list_size)
return (NULL);
return (&ARRAY_ITEM(&data->list, idx));
return (&data->list[idx]);
}
void
@@ -520,10 +549,10 @@ window_choose_key(struct window_pane *wp, __unused struct client *c,
u_int items, n;
int idx;
items = ARRAY_LENGTH(&data->list);
items = data->list_size;
if (data->input_type == WINDOW_CHOOSE_GOTO_ITEM) {
switch (mode_key_lookup(&data->mdata, key, NULL)) {
switch (mode_key_lookup(&data->mdata, key, NULL, NULL)) {
case MODEKEYCHOICE_CANCEL:
data->input_type = WINDOW_CHOOSE_NORMAL;
window_choose_redraw_screen(wp);
@@ -535,8 +564,7 @@ window_choose_key(struct window_pane *wp, __unused struct client *c,
window_choose_redraw_screen(wp);
break;
}
item = &ARRAY_ITEM(&data->list, n);
window_choose_fire_callback(wp, item->wcd);
window_choose_fire_callback(wp, data->list[n].wcd);
break;
case MODEKEYCHOICE_BACKSPACE:
input_len = strlen(data->input_str);
@@ -554,7 +582,7 @@ window_choose_key(struct window_pane *wp, __unused struct client *c,
return;
}
switch (mode_key_lookup(&data->mdata, key, NULL)) {
switch (mode_key_lookup(&data->mdata, key, NULL, NULL)) {
case MODEKEYCHOICE_CANCEL:
window_choose_fire_callback(wp, NULL);
break;
@@ -733,12 +761,10 @@ window_choose_key(struct window_pane *wp, __unused struct client *c,
break;
default:
idx = window_choose_index_key(data, key);
if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list))
if (idx < 0 || (u_int) idx >= data->list_size)
break;
data->selected = idx;
item = &ARRAY_ITEM(&data->list, data->selected);
window_choose_fire_callback(wp, item->wcd);
window_choose_fire_callback(wp, data->list[idx].wcd);
break;
}
}
@@ -765,8 +791,8 @@ window_choose_write_line(struct window_pane *wp, struct screen_write_ctx *ctx,
style_apply(&gc, oo, "mode-style");
screen_write_cursormove(ctx, 0, py);
if (data->top + py < ARRAY_LENGTH(&data->list)) {
item = &ARRAY_ITEM(&data->list, data->top + py);
if (data->top + py < data->list_size) {
item = &data->list[data->top + py];
if (item->wcd->wl != NULL &&
item->wcd->wl->flags & WINLINK_ALERTFLAGS)
gc.attr |= GRID_ATTR_BRIGHT;
@@ -811,7 +837,7 @@ window_choose_key_index(struct window_choose_mode_data *data, u_int idx)
int mkey;
for (ptr = keys; *ptr != '\0'; ptr++) {
mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
mkey = mode_key_lookup(&data->mdata, *ptr, NULL, NULL);
if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
continue;
if (idx-- == 0)
@@ -831,7 +857,7 @@ window_choose_index_key(struct window_choose_mode_data *data, key_code key)
u_int idx = 0;
for (ptr = keys; *ptr != '\0'; ptr++) {
mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
mkey = mode_key_lookup(&data->mdata, *ptr, NULL, NULL);
if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
continue;
if (key == (key_code)*ptr)
@@ -881,7 +907,7 @@ window_choose_scroll_down(struct window_pane *wp)
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
if (data->top >= ARRAY_LENGTH(&data->list))
if (data->top >= data->list_size)
return;
data->top++;

View File

@@ -230,7 +230,7 @@ window_clock_draw_screen(struct window_pane *wp)
screen_write_cursormove(&ctx, x, y);
memcpy(&gc, &grid_default_cell, sizeof gc);
colour_set_fg(&gc, colour);
gc.fg = colour;
screen_write_puts(&ctx, &gc, "%s", tim);
}
@@ -242,7 +242,7 @@ window_clock_draw_screen(struct window_pane *wp)
y = (screen_size_y(s) / 2) - 3;
memcpy(&gc, &grid_default_cell, sizeof gc);
colour_set_bg(&gc, colour);
gc.bg = colour;
for (ptr = tim; *ptr != '\0'; ptr++) {
if (*ptr >= '0' && *ptr <= '9')
idx = *ptr - '0';

View File

@@ -26,7 +26,9 @@
struct screen *window_copy_init(struct window_pane *);
void window_copy_free(struct window_pane *);
void window_copy_pagedown(struct window_pane *);
void window_copy_pagedown(struct window_pane *, int);
void window_copy_next_paragraph(struct window_pane *);
void window_copy_previous_paragraph(struct window_pane *);
void window_copy_resize(struct window_pane *, u_int, u_int);
void window_copy_key(struct window_pane *, struct client *, struct session *,
key_code, struct mouse_event *);
@@ -48,8 +50,14 @@ int window_copy_search_lr(struct grid *, struct grid *, u_int *, u_int,
u_int, u_int, int);
int window_copy_search_rl(struct grid *, struct grid *, u_int *, u_int,
u_int, u_int, int);
void window_copy_search_up(struct window_pane *, const char *);
void window_copy_search_down(struct window_pane *, const char *);
void window_copy_move_left(struct screen *, u_int *, u_int *);
void window_copy_move_right(struct screen *, u_int *, u_int *);
int window_copy_is_lowercase(const char *);
void window_copy_search_jump(struct window_pane *, struct grid *,
struct grid *, u_int, u_int, u_int, int, int, int);
void window_copy_search(struct window_pane *, const char *, int, int);
void window_copy_search_up(struct window_pane *, const char *, int);
void window_copy_search_down(struct window_pane *, const char *, int);
void window_copy_goto_line(struct window_pane *, const char *);
void window_copy_update_cursor(struct window_pane *, u_int, u_int);
void window_copy_start_selection(struct window_pane *);
@@ -321,7 +329,7 @@ window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
}
void
window_copy_pageup(struct window_pane *wp)
window_copy_pageup(struct window_pane *wp, int half_page)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
@@ -340,8 +348,12 @@ window_copy_pageup(struct window_pane *wp)
data->cx = data->lastcx;
n = 1;
if (screen_size_y(s) > 2)
n = screen_size_y(s) - 2;
if (screen_size_y(s) > 2) {
if (half_page)
n = screen_size_y(s) / 2;
else
n = screen_size_y(s) - 2;
}
if (data->oy + n > screen_hsize(data->backing))
data->oy = screen_hsize(data->backing);
@@ -360,7 +372,7 @@ window_copy_pageup(struct window_pane *wp)
}
void
window_copy_pagedown(struct window_pane *wp)
window_copy_pagedown(struct window_pane *wp, int half_page)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
@@ -379,8 +391,12 @@ window_copy_pagedown(struct window_pane *wp)
data->cx = data->lastcx;
n = 1;
if (screen_size_y(s) > 2)
n = screen_size_y(s) - 2;
if (screen_size_y(s) > 2) {
if (half_page)
n = screen_size_y(s) / 2;
else
n = screen_size_y(s) - 2;
}
if (data->oy < n)
data->oy = 0;
@@ -403,6 +419,43 @@ window_copy_pagedown(struct window_pane *wp)
window_copy_redraw_screen(wp);
}
void
window_copy_previous_paragraph(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
u_int oy;
oy = screen_hsize(data->backing) + data->cy - data->oy;
while (oy > 0 && window_copy_find_length(wp, oy) == 0)
oy--;
while (oy > 0 && window_copy_find_length(wp, oy) > 0)
oy--;
window_copy_scroll_to(wp, 0, oy);
}
void
window_copy_next_paragraph(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
u_int maxy, ox, oy;
oy = screen_hsize(data->backing) + data->cy - data->oy;
maxy = screen_hsize(data->backing) + screen_size_y(s) - 1;
while (oy < maxy && window_copy_find_length(wp, oy) == 0)
oy++;
while (oy < maxy && window_copy_find_length(wp, oy) > 0)
oy++;
ox = window_copy_find_length(wp, oy);
window_copy_scroll_to(wp, ox, oy);
}
void
window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
{
@@ -437,7 +490,7 @@ window_copy_key(struct window_pane *wp, struct client *c, struct session *sess,
const char *word_separators;
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
u_int n, np;
u_int np;
int keys;
enum mode_key_cmd cmd;
const char *arg, *ss;
@@ -485,7 +538,9 @@ window_copy_key(struct window_pane *wp, struct client *c, struct session *sess,
return;
}
cmd = mode_key_lookup(&data->mdata, key, &arg);
cmd = mode_key_lookup(&data->mdata, key, &arg, &np);
if (data->numprefix > 0)
np = data->numprefix;
if (cmd != MODEKEYCOPY_PREVIOUSPAGE &&
cmd != MODEKEYCOPY_NEXTPAGE &&
cmd != MODEKEYCOPY_SCROLLUP &&
@@ -542,37 +597,27 @@ window_copy_key(struct window_pane *wp, struct client *c, struct session *sess,
break;
case MODEKEYCOPY_PREVIOUSPAGE:
for (; np != 0; np--)
window_copy_pageup(wp);
window_copy_pageup(wp, 0);
break;
case MODEKEYCOPY_NEXTPAGE:
for (; np != 0; np--)
window_copy_pagedown(wp);
window_copy_pagedown(wp, 0);
break;
case MODEKEYCOPY_PREVIOUSPARAGRAPH:
for (; np != 0; np--)
window_copy_previous_paragraph(wp);
break;
case MODEKEYCOPY_NEXTPARAGRAPH:
for (; np != 0; np--)
window_copy_next_paragraph(wp);
break;
case MODEKEYCOPY_HALFPAGEUP:
n = screen_size_y(s) / 2;
for (; np != 0; np--) {
if (data->oy + n > screen_hsize(data->backing))
data->oy = screen_hsize(data->backing);
else
data->oy += n;
}
window_copy_update_selection(wp, 1);
window_copy_redraw_screen(wp);
for (; np != 0; np--)
window_copy_pageup(wp, 1);
break;
case MODEKEYCOPY_HALFPAGEDOWN:
n = screen_size_y(s) / 2;
for (; np != 0; np--) {
if (data->oy < n)
data->oy = 0;
else
data->oy -= n;
}
if (data->scroll_exit && data->oy == 0) {
window_pane_reset_mode(wp);
return;
}
window_copy_update_selection(wp, 1);
window_copy_redraw_screen(wp);
for (; np != 0; np--)
window_copy_pagedown(wp, 1);
break;
case MODEKEYCOPY_TOPLINE:
data->cx = 0;
@@ -778,20 +823,20 @@ window_copy_key(struct window_pane *wp, struct client *c, struct session *sess,
ss = data->searchstr;
if (cmd == MODEKEYCOPY_SEARCHAGAIN) {
for (; np != 0; np--)
window_copy_search_up(wp, ss);
window_copy_search_up(wp, ss, 1);
} else {
for (; np != 0; np--)
window_copy_search_down(wp, ss);
window_copy_search_down(wp, ss, 1);
}
break;
case WINDOW_COPY_SEARCHDOWN:
ss = data->searchstr;
if (cmd == MODEKEYCOPY_SEARCHAGAIN) {
for (; np != 0; np--)
window_copy_search_down(wp, ss);
window_copy_search_down(wp, ss, 1);
} else {
for (; np != 0; np--)
window_copy_search_up(wp, ss);
window_copy_search_up(wp, ss, 1);
}
break;
}
@@ -857,11 +902,11 @@ window_copy_key_input(struct window_pane *wp, key_code key)
struct screen *s = &data->screen;
const char *bufdata;
size_t inputlen, n, bufsize;
int np;
u_int np;
struct paste_buffer *pb;
u_char ch;
switch (mode_key_lookup(&data->mdata, key, NULL)) {
switch (mode_key_lookup(&data->mdata, key, NULL, &np)) {
case MODEKEYEDIT_CANCEL:
data->numprefix = -1;
return (-1);
@@ -889,10 +934,8 @@ window_copy_key_input(struct window_pane *wp, key_code key)
data->inputstr[inputlen + n] = '\0';
break;
case MODEKEYEDIT_ENTER:
np = data->numprefix;
if (np <= 0)
np = 1;
if (data->numprefix > 0)
np = data->numprefix;
switch (data->inputtype) {
case WINDOW_COPY_OFF:
case WINDOW_COPY_JUMPFORWARD:
@@ -902,16 +945,16 @@ window_copy_key_input(struct window_pane *wp, key_code key)
case WINDOW_COPY_NUMERICPREFIX:
break;
case WINDOW_COPY_SEARCHUP:
for (; np != 0; np--)
window_copy_search_up(wp, data->inputstr);
data->searchtype = data->inputtype;
data->searchstr = xstrdup(data->inputstr);
for (; np != 0; np--)
window_copy_search_up(wp, data->inputstr, 0);
break;
case WINDOW_COPY_SEARCHDOWN:
for (; np != 0; np--)
window_copy_search_down(wp, data->inputstr);
data->searchtype = data->inputtype;
data->searchstr = xstrdup(data->inputstr);
for (; np != 0; np--)
window_copy_search_down(wp, data->inputstr, 0);
break;
case WINDOW_COPY_NAMEDBUFFER:
window_copy_copy_selection(wp, data->inputstr);
@@ -1063,136 +1106,141 @@ window_copy_search_rl(struct grid *gd,
}
void
window_copy_search_up(struct window_pane *wp, const char *searchstr)
window_copy_move_left(struct screen *s, u_int *fx, u_int *fy)
{
if (*fx == 0) { /* left */
if (*fy == 0) /* top */
return;
*fx = screen_size_x(s) - 1;
*fy = *fy - 1;
} else
*fx = *fx - 1;
}
void
window_copy_move_right(struct screen *s, u_int *fx, u_int *fy)
{
if (*fx == screen_size_x(s) - 1) { /* right */
if (*fy == screen_hsize(s) + screen_size_y(s)) /* bottom */
return;
*fx = 0;
*fy = *fy + 1;
} else
*fx = *fx + 1;
}
int
window_copy_is_lowercase(const char *ptr)
{
while (*ptr != '\0') {
if (*ptr != tolower((u_char)*ptr))
return (0);
++ptr;
}
return (1);
}
/*
* Search for text stored in sgd starting from position fx,fy up to endline. If
* found, jump to it. If cis then ignore case. The direction is 0 for searching
* up, down otherwise. If wrap then go to begin/end of grid and try again if
* not found.
*/
void
window_copy_search_jump(struct window_pane *wp, struct grid *gd,
struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap,
int direction)
{
u_int i, px;
int found;
found = 0;
if (direction) {
for (i = fy; i <= endline; i++) {
found = window_copy_search_lr(gd, sgd, &px, i, fx,
gd->sx, cis);
if (found)
break;
fx = 0;
}
} else {
for (i = fy + 1; endline < i; i--) {
found = window_copy_search_rl(gd, sgd, &px, i - 1, 0,
fx, cis);
if (found) {
i--;
break;
}
fx = gd->sx;
}
}
if (found)
window_copy_scroll_to(wp, px, i);
else if (wrap) {
window_copy_search_jump(wp, gd, sgd, direction ? 0 : gd->sx - 1,
direction ? 0 : gd->hsize + gd->sy - 1, fy, cis, 0,
direction);
}
}
/*
* Search in for text searchstr. If direction is 0 then search up, otherwise
* down. If moveflag is 0 then look for string at the current cursor position
* as well.
*/
void
window_copy_search(struct window_pane *wp, const char *searchstr, int direction,
int moveflag)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = data->backing, ss;
struct screen_write_ctx ctx;
struct grid *gd = s->grid, *sgd;
struct grid_cell gc;
size_t searchlen;
u_int i, last, fx, fy, px;
int n, wrapped, wrapflag, cis;
const char *ptr;
if (*searchstr == '\0')
return;
wrapflag = options_get_number(wp->window->options, "wrap-search");
searchlen = screen_write_strlen("%s", searchstr);
screen_init(&ss, searchlen, 1, 0);
screen_write_start(&ctx, NULL, &ss);
memcpy(&gc, &grid_default_cell, sizeof gc);
screen_write_nputs(&ctx, -1, &gc, "%s", searchstr);
screen_write_stop(&ctx);
struct grid *gd = s->grid;
u_int fx, fy, endline;
int wrapflag, cis;
fx = data->cx;
fy = gd->hsize - data->oy + data->cy;
fy = screen_hsize(data->backing) - data->oy + data->cy;
if (fx == 0) {
if (fy == 0)
return;
fx = gd->sx - 1;
fy--;
} else
fx--;
n = wrapped = 0;
screen_init(&ss, screen_write_strlen("%s", searchstr), 1, 0);
screen_write_start(&ctx, NULL, &ss);
screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", searchstr);
screen_write_stop(&ctx);
cis = 1;
for (ptr = searchstr; *ptr != '\0'; ptr++) {
if (*ptr != tolower((u_char)*ptr)) {
cis = 0;
break;
}
if (moveflag) {
if (direction)
window_copy_move_right(s, &fx, &fy);
else
window_copy_move_left(s, &fx, &fy);
}
window_copy_clear_selection(wp);
retry:
sgd = ss.grid;
for (i = fy + 1; i > 0; i--) {
last = screen_size_x(s);
if (i == fy + 1)
last = fx;
n = window_copy_search_rl(gd, sgd, &px, i - 1, 0, last, cis);
if (n) {
window_copy_scroll_to(wp, px, i - 1);
break;
}
}
if (wrapflag && !n && !wrapped) {
fx = gd->sx - 1;
fy = gd->hsize + gd->sy - 1;
wrapped = 1;
goto retry;
}
wrapflag = options_get_number(wp->window->options, "wrap-search");
cis = window_copy_is_lowercase(searchstr);
if (direction)
endline = gd->hsize + gd->sy - 1;
else
endline = 0;
window_copy_search_jump(wp, gd, ss.grid, fx, fy, endline, cis, wrapflag,
direction);
screen_free(&ss);
}
void
window_copy_search_down(struct window_pane *wp, const char *searchstr)
window_copy_search_up(struct window_pane *wp, const char *searchstr,
int moveflag)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = data->backing, ss;
struct screen_write_ctx ctx;
struct grid *gd = s->grid, *sgd;
struct grid_cell gc;
size_t searchlen;
u_int i, first, fx, fy, px;
int n, wrapped, wrapflag, cis;
const char *ptr;
window_copy_search(wp, searchstr, 0, moveflag);
}
if (*searchstr == '\0')
return;
wrapflag = options_get_number(wp->window->options, "wrap-search");
searchlen = screen_write_strlen("%s", searchstr);
screen_init(&ss, searchlen, 1, 0);
screen_write_start(&ctx, NULL, &ss);
memcpy(&gc, &grid_default_cell, sizeof gc);
screen_write_nputs(&ctx, -1, &gc, "%s", searchstr);
screen_write_stop(&ctx);
fx = data->cx;
fy = gd->hsize - data->oy + data->cy;
if (fx == gd->sx - 1) {
if (fy == gd->hsize + gd->sy)
return;
fx = 0;
fy++;
} else
fx++;
n = wrapped = 0;
cis = 1;
for (ptr = searchstr; *ptr != '\0'; ptr++) {
if (*ptr != tolower((u_char)*ptr)) {
cis = 0;
break;
}
}
retry:
sgd = ss.grid;
for (i = fy + 1; i < gd->hsize + gd->sy + 1; i++) {
first = 0;
if (i == fy + 1)
first = fx;
n = window_copy_search_lr(gd, sgd, &px, i - 1, first, gd->sx,
cis);
if (n) {
window_copy_scroll_to(wp, px, i - 1);
break;
}
}
if (wrapflag && !n && !wrapped) {
fx = 0;
fy = 0;
wrapped = 1;
goto retry;
}
screen_free(&ss);
void
window_copy_search_down(struct window_pane *wp, const char *searchstr,
int moveflag)
{
window_copy_search(wp, searchstr, 1, moveflag);
}
void

133
window.c
View File

@@ -17,6 +17,7 @@
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
@@ -26,6 +27,7 @@
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#include "tmux.h"
@@ -54,15 +56,17 @@ struct windows windows;
/* Global panes tree. */
struct window_pane_tree all_window_panes;
u_int next_window_pane_id;
u_int next_window_id;
u_int next_active_point;
static u_int next_window_pane_id;
static u_int next_window_id;
static u_int next_active_point;
void window_pane_timer_callback(int, short, void *);
void window_pane_read_callback(struct bufferevent *, void *);
void window_pane_error_callback(struct bufferevent *, short, void *);
static void window_pane_set_watermark(struct window_pane *, size_t);
struct window_pane *window_pane_choose_best(struct window_pane **, u_int);
static void window_pane_read_callback(struct bufferevent *, void *);
static void window_pane_error_callback(struct bufferevent *, short, void *);
static struct window_pane *window_pane_choose_best(struct window_pane **,
u_int);
RB_GENERATE(windows, window, entry, window_cmp);
@@ -291,7 +295,7 @@ window_create1(u_int sx, u_int sy)
w = xcalloc(1, sizeof *w);
w->name = NULL;
w->flags = 0;
w->flags = WINDOW_STYLECHANGED;
TAILQ_INIT(&w->panes);
w->active = NULL;
@@ -323,7 +327,7 @@ window_create(const char *name, int argc, char **argv, const char *path,
struct window_pane *wp;
w = window_create1(sx, sy);
wp = window_add_pane(w, hlimit);
wp = window_add_pane(w, NULL, hlimit);
layout_init(w, wp);
if (window_pane_spawn(wp, argc, argv, path, shell, cwd, env, tio,
@@ -553,15 +557,19 @@ window_unzoom(struct window *w)
}
struct window_pane *
window_add_pane(struct window *w, u_int hlimit)
window_add_pane(struct window *w, struct window_pane *after, u_int hlimit)
{
struct window_pane *wp;
wp = window_pane_create(w, w->sx, w->sy, hlimit);
if (TAILQ_EMPTY(&w->panes))
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
else
TAILQ_INSERT_AFTER(&w->panes, w->active, wp, entry);
else {
if (after == NULL)
TAILQ_INSERT_AFTER(&w->panes, w->active, wp, entry);
else
TAILQ_INSERT_AFTER(&w->panes, after, wp, entry);
}
return (wp);
}
@@ -764,6 +772,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
screen_init(&wp->base, sx, sy, hlimit);
wp->screen = &wp->base;
screen_init(&wp->status_screen, 1, 1, 0);
if (gethostname(host, sizeof host) == 0)
screen_set_title(&wp->base, host);
@@ -777,9 +787,6 @@ window_pane_destroy(struct window_pane *wp)
{
window_pane_reset_mode(wp);
if (event_initialized(&wp->timer))
evtimer_del(&wp->timer);
if (wp->fd != -1) {
#ifdef HAVE_UTEMPTER
utempter_remove_record(wp->fd);
@@ -799,6 +806,9 @@ window_pane_destroy(struct window_pane *wp)
close(wp->pipe_fd);
}
if (event_initialized(&wp->resize_timer))
event_del(&wp->resize_timer);
RB_REMOVE(window_pane_tree, &all_window_panes, wp);
free((void *)wp->cwd);
@@ -807,6 +817,14 @@ window_pane_destroy(struct window_pane *wp)
free(wp);
}
static void
window_pane_set_watermark(struct window_pane *wp, size_t size)
{
wp->wmark_hits = 0;
wp->wmark_size = size;
bufferevent_setwatermark(wp->event, EV_READ, 0, size);
}
int
window_pane_spawn(struct window_pane *wp, int argc, char **argv,
const char *path, const char *shell, const char *cwd, struct environ *env,
@@ -843,6 +861,7 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
log_debug("spawn: %s -- %s", wp->shell, cmd);
for (i = 0; i < wp->argc; i++)
log_debug("spawn: argv[%d] = %s", i, wp->argv[i]);
environ_log(env, "spawn: ");
memset(&ws, 0, sizeof ws);
ws.ws_col = screen_size_x(&wp->base);
@@ -924,44 +943,37 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL,
window_pane_error_callback, wp);
bufferevent_setwatermark(wp->event, EV_READ, 0, READ_SIZE);
window_pane_set_watermark(wp, READ_FAST_SIZE);
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
free(cmd);
return (0);
}
void
window_pane_timer_callback(__unused int fd, __unused short events, void *data)
{
window_pane_read_callback(NULL, data);
}
void
static void
window_pane_read_callback(__unused struct bufferevent *bufev, void *data)
{
struct window_pane *wp = data;
struct evbuffer *evb = wp->event->input;
size_t size = EVBUFFER_LENGTH(evb);
char *new_data;
size_t new_size, available;
struct client *c;
struct timeval tv;
size_t new_size;
if (event_initialized(&wp->timer))
evtimer_del(&wp->timer);
log_debug("%%%u has %zu bytes", wp->id, EVBUFFER_LENGTH(evb));
TAILQ_FOREACH(c, &clients, entry) {
if (!tty_client_ready(c, wp))
continue;
available = EVBUFFER_LENGTH(c->tty.event->output);
if (available > READ_BACKOFF)
goto start_timer;
if (wp->wmark_size == READ_FAST_SIZE) {
if (size > READ_FULL_SIZE)
wp->wmark_hits++;
if (wp->wmark_hits == READ_CHANGE_HITS)
window_pane_set_watermark(wp, READ_SLOW_SIZE);
} else if (wp->wmark_size == READ_SLOW_SIZE) {
if (size < READ_EMPTY_SIZE)
wp->wmark_hits++;
if (wp->wmark_hits == READ_CHANGE_HITS)
window_pane_set_watermark(wp, READ_FAST_SIZE);
}
log_debug("%%%u has %zu bytes (of %u, %u hits)", wp->id, size,
wp->wmark_size, wp->wmark_hits);
new_size = EVBUFFER_LENGTH(evb) - wp->pipe_off;
new_size = size - wp->pipe_off;
if (wp->pipe_fd != -1 && new_size > 0) {
new_data = EVBUFFER_DATA(evb) + wp->pipe_off;
bufferevent_write(wp->pipe_event, new_data, new_size);
@@ -969,21 +981,10 @@ window_pane_read_callback(__unused struct bufferevent *bufev, void *data)
input_parse(wp);
wp->pipe_off = EVBUFFER_LENGTH(evb);
return;
start_timer:
log_debug("%%%u backing off (%s %zu > %d)", wp->id, c->ttyname,
available, READ_BACKOFF);
tv.tv_sec = 0;
tv.tv_usec = READ_TIME;
evtimer_set(&wp->timer, window_pane_timer_callback, wp);
evtimer_add(&wp->timer, &tv);
wp->pipe_off = size;
}
void
static void
window_pane_error_callback(__unused struct bufferevent *bufev,
__unused short what, void *data)
{
@@ -1088,15 +1089,38 @@ window_pane_alternate_off(struct window_pane *wp, struct grid_cell *gc,
wp->flags |= PANE_REDRAW;
}
static void
window_pane_mode_timer(__unused int fd, __unused short events, void *arg)
{
struct window_pane *wp = arg;
struct timeval tv = { .tv_sec = 10 };
int n = 0;
evtimer_del(&wp->modetimer);
evtimer_add(&wp->modetimer, &tv);
log_debug("%%%u in mode: last=%ld", wp->id, (long)wp->modelast);
if (wp->modelast < time(NULL) - WINDOW_MODE_TIMEOUT) {
if (ioctl(wp->fd, FIONREAD, &n) == -1 || n > 0)
window_pane_reset_mode(wp);
}
}
int
window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode)
{
struct screen *s;
struct timeval tv = { .tv_sec = 10 };
if (wp->mode != NULL)
return (1);
wp->mode = mode;
wp->modelast = time(NULL);
evtimer_set(&wp->modetimer, window_pane_mode_timer, wp);
evtimer_add(&wp->modetimer, &tv);
if ((s = wp->mode->init(wp)) != NULL)
wp->screen = s;
wp->flags |= (PANE_REDRAW|PANE_CHANGED);
@@ -1111,6 +1135,8 @@ window_pane_reset_mode(struct window_pane *wp)
if (wp->mode == NULL)
return;
evtimer_del(&wp->modetimer);
wp->mode->free(wp);
wp->mode = NULL;
@@ -1130,6 +1156,7 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
return;
if (wp->mode != NULL) {
wp->modelast = time(NULL);
if (wp->mode->key != NULL)
wp->mode->key(wp, c, s, key, m);
return;
@@ -1195,7 +1222,7 @@ window_pane_search(struct window_pane *wp, const char *searchstr,
}
/* Get MRU pane from a list. */
struct window_pane *
static struct window_pane *
window_pane_choose_best(struct window_pane **list, u_int size)
{
struct window_pane *next, *best;