119 Commits
1.2 ... 1.3

Author SHA1 Message Date
no_author
946fd162ba This commit was manufactured by cvs2svn to create tag 'TMUX_1_3'. 2010-07-18 13:41:00 +00:00
Tiago Cunha
9b47a48393 Changes for 1.3. 2010-07-18 13:40:59 +00:00
Tiago Cunha
0482983d53 Done. 2010-07-18 13:39:02 +00:00
Tiago Cunha
2b512dc49d Bump VERSION, and comment FDEBUG. 2010-07-18 13:36:52 +00:00
Tiago Cunha
ae45c2ea45 Sync OpenBSD patchset 736:
some escapes i missed;
2010-07-17 14:39:01 +00:00
Tiago Cunha
11f81e8134 Sync OpenBSD patchset 735:
Make pane/window wrapping more logical (so with 10 windows, +10 from
window 5 stays in the same place), and tidy the code. From Tiago Cunha.
2010-07-17 14:38:13 +00:00
Tiago Cunha
ad6a528f61 Sync OpenBSD patchset 734:
Return the command client return code with MSG_EXIT now that MSG_ERROR and
MSG_PRINT are unused.

New clients should be compatible with old tmux servers but vice versa may print
an error.
2010-07-17 14:36:41 +00:00
Tiago Cunha
46f27eab22 Sync OpenBSD patchset 733:
replace some magic mouse constants with defines for clarity. ok nicm
2010-07-02 02:56:07 +00:00
Tiago Cunha
e4703bacb5 Sync OpenBSD patchset 732:
Custom layouts. list-windows command displays the layout as a string (such as
"bb62,159x48,0,0{79x48,0,0,79x48,80,0}") and it can be applied to another
window (with the same number of panes or fewer) using select-layout.
2010-07-02 02:54:52 +00:00
Tiago Cunha
e4573de97b Sync OpenBSD patchset 731:
Send all three of stdin, stdout, stderr from the client to the server, so that
commands can directly make use of them. This means that load-buffer and
save-buffer can have "-" as the file to read from stdin or write to stdout.

This is a protocol version bump so the tmux server will need to be restarted
after upgrade (or an older client used).
2010-07-02 02:52:13 +00:00
Tiago Cunha
63e76b555d Sync OpenBSD patchset 730:
Store the current working directory in the session, change the default-path
option to default to empty and make that mean that the stored session CWD is
used.
2010-07-02 02:49:19 +00:00
Tiago Cunha
13e7f060b1 Update. 2010-07-02 02:46:39 +00:00
Tiago Cunha
fa34c76275 Sync OpenBSD patchset 729:
New option, detach-on-destroy, to set what happens to a client when the session
it is attached to is destroyed. If on (the default), it is detached; if off, it
is switched to the most recently active session.
2010-07-02 02:45:52 +00:00
Tiago Cunha
985cd3a4de Sync OpenBSD patchset 728:
Use server_destroy_session() for kill-session.
2010-07-02 02:43:50 +00:00
Tiago Cunha
03c1c1cd9f Sync OpenBSD patchset 727:
Setting the cmdlist pointer in the bind-key to NULL to prevent it being freed
after the command is executing is bogus because it may still be needed if the
same command is going to be executed again (for example if you "bind-key a
bind-key b ..."). Making a copy is hard, so instead add a reference count to
the cmd_list.

While here, also print bind-key -n and the rest of the flags properly.

Fixes problem reported by mcbride@.
2010-07-02 02:43:01 +00:00
Tiago Cunha
0e70c8801c Update. 2010-06-22 23:37:28 +00:00
Tiago Cunha
617386370b Nuke vis.h. 2010-06-22 23:36:54 +00:00
Tiago Cunha
bf1e237410 Sync OpenBSD patchset 726:
Add a choose-buffer command for easier use of the paste buffer stack.
2010-06-22 23:35:20 +00:00
Tiago Cunha
8d3b726396 Sync OpenBSD patchset 725:
Extend the -t:+ and -t:- window targets for next and previous window to
accept an offset such as -t:+2. From Tiago Cunha.
2010-06-22 23:29:05 +00:00
Tiago Cunha
47b335dee7 Sync OpenBSD patchset 724:
Having a list of winlinks->alerts for each session is stupid, just store
the alert flags directly in the winlink itself.
2010-06-22 23:26:18 +00:00
Tiago Cunha
6c76724201 Sync OpenBSD patchset 723:
Rename activity->alert in a couple of functions for consistency.
2010-06-22 23:22:31 +00:00
Tiago Cunha
29434cb043 Sync OpenBSD patchset 722:
Give tmux sockets (but not the containing folder) group
permissions. This allows hardlinks to the sockets to be used more
easily.
2010-06-22 23:21:39 +00:00
Nicholas Marriott
b7454e37cb Done. 2010-06-21 00:19:44 +00:00
Nicholas Marriott
e2a5e02022 +. 2010-06-21 00:13:13 +00:00
Micah Cowan
cac532c3d1 Ensure we overwrite wide characters properly, and never overwrite characters we weren't overlapping.
Fixes "disappearing wide characters" glitch.
2010-06-16 18:09:23 +00:00
Tiago Cunha
e186450788 Sync OpenBSD patchset 720:
Last change erroneously used the target argument for looking up the
client which caused pipe-pane to fail when used from the command
line. Instead pass NULL which should use the current client.

Spotted by Tiago Cunha.
2010-06-15 20:25:40 +00:00
Tiago Cunha
3e8092709c Sync OpenBSD patchset 719:
Add a missing command and some missing Ic, from Tiago Cunha.
2010-06-15 20:24:52 +00:00
Nicholas Marriott
1b77ae2684 +. 2010-06-13 11:28:26 +00:00
Tiago Cunha
60134cebda imsg was moved into libutil on OpenBSD. 2010-06-06 13:00:47 +00:00
Tiago Cunha
f34861bad4 Sync OpenBSD patchset 717:
Couple of missing command aliases/flags, from Tiago Cunha.
2010-06-06 00:31:32 +00:00
Tiago Cunha
6503207185 Sync OpenBSD patchset 716:
Fix problems with window sizing seen by Raghavendra D Prabhu when
starting tmux from .xinitrc.

One of the very few things the server relies on the client for now is to
pass through a message on SIGWINCH, but there is a condition where
potentially a SIGWINCH may be lost during the transition from unattached
(main.c) to attached (client.c). So trigger a size change immediately
after the client installs its SIGWINCH handler.

Also, when the terminal is resized, reset the scroll region and cursor
position. Previously, we were clearing our saved idea of these, but in
fact some terminals do not reset them on resize, so this caused problems
during redraw.

While here make a resize to the same size not cause a redraw and rename
the tmux.out output log file to include the tmux PID.
2010-06-06 00:30:34 +00:00
Tiago Cunha
3bba401609 Sync OpenBSD patchset 715:
Support the status_replace # replacement sequences in the pipe-pane
command, thanks to Andrea Barisani.
2010-06-06 00:28:00 +00:00
Tiago Cunha
31657820bc Sync OpenBSD patchset 714:
Shut up gcc4 warnings.
2010-06-06 00:27:08 +00:00
Tiago Cunha
be3643fba0 Sync OpenBSD patchset 713:
This ioctl(TIOCGWINSZ) call is no longer necessary, the result is never
used and the server now does it later on the tty fd directly.
2010-06-06 00:25:47 +00:00
Tiago Cunha
f62d3d22bb Sync OpenBSD patchset 710:
When the mode-mouse option is on, support dragging to make a selection
in copy mode.

Also support the scroll wheel, although xterm strangely does not ignore
it in application mouse mode, causing redraw artifacts when scrolling up
(other terminals appear to be better behaved).
2010-06-06 00:23:44 +00:00
Tiago Cunha
67dc249d0e Sync OpenBSD patchset 709:
Better to say "command key bindings" since we've just called them
command keys.
2010-06-06 00:21:36 +00:00
Tiago Cunha
0778ef230b Sync OpenBSD patchset 708:
There is no real reason not to list all the key bindings here rather
than just a selection.
2010-06-06 00:20:53 +00:00
Tiago Cunha
bebfd7c2c8 Sync OpenBSD patchset 706:
Rename some imsg bits to make namespace collisions less likely buf to
ibuf, buf_read to ibuf_read, READ_BUF_SIZE to IBUF_READ_SIZE.
2010-06-06 00:08:28 +00:00
Tiago Cunha
348c3e69de Sync OpenBSD patchset 705:
Don't die if the client has been detached when the job finishes, just
don't display the output.
2010-06-06 00:04:59 +00:00
Tiago Cunha
0d6a64070c Sync OpenBSD patchset 704:
Fix an out-of-date comment.
2010-06-06 00:04:18 +00:00
Tiago Cunha
bb4d770e45 No vis.h in here. 2010-06-06 00:03:02 +00:00
Tiago Cunha
e55a59eebc Sync OpenBSD patchset 702:
Enhance paste-buffer to allow lines to be separated by any string, from
Andrea Barisani.
2010-06-06 00:01:36 +00:00
Tiago Cunha
11cd05db27 Sync OpenBSD patchset 701:
Colour+attribute options for status line alerts, from Alex Alexander.
2010-06-05 23:56:29 +00:00
Tiago Cunha
6c6255f2d7 Sync OpenBSD patchset 700:
Accept (and document) "none" instead of "default" for attributes as it
is clearer and avoids confusion with default colours.
2010-06-05 23:54:51 +00:00
Micah Cowan
227e458ebb Use a macro-based mask for obtaining a key or modifier-set from the combination.
Display C-@, etc, as C-Space, in list-keys.
2010-06-05 20:29:11 +00:00
Nicholas Marriott
89eb95265a Must allocate for putenv. 2010-06-05 18:20:48 +00:00
Nicholas Marriott
d98efa5378 Only need to build setenv.c once. 2010-06-05 18:14:29 +00:00
Nicholas Marriott
a9c6976268 Should be const char *. 2010-06-05 16:29:40 +00:00
Micah Cowan
d9c99b83c7 Make double start-of-line do what double end-of-line does, on wrapped lines. 2010-06-05 07:48:35 +00:00
Micah Cowan
d27956f160 Allow C-Space to work correctly once again, and forbid nonsensical combinations such as C-Enter or C-Escape. 2010-06-05 06:27:19 +00:00
Nicholas Marriott
e334deb872 +. 2010-05-27 08:29:17 +00:00
Nicholas Marriott
e50dc0745f +. 2010-05-24 18:21:07 +00:00
Micah Cowan
f11f71752a Pass in the session, rather than the client, to window modes' key() function.
We were only ever using the client to find the session anyway.
2010-05-22 21:56:04 +00:00
Nicholas Marriott
9e7a5fa5ef Spacing nits. 2010-05-19 21:49:57 +00:00
Nicholas Marriott
9c01a3d0db Solaris 9 is missing CMSG_ALIGN and some of the RFC2292 CMSG_*. From
Dagobert Michelsen.
2010-05-19 21:40:49 +00:00
Nicholas Marriott
278effd7ea Solaris 9 doesn't have setenv and unsetenv so add compat versions, based
on code from Dagobert Michelsen.
2010-05-19 21:31:39 +00:00
Nicholas Marriott
59c13133de Fix bad merge, from Romain Francoise. 2010-05-16 17:50:31 +00:00
Nicholas Marriott
41afc38dcc +. 2010-05-14 19:05:06 +00:00
Tiago Cunha
0beb31c261 Update. 2010-05-14 14:38:50 +00:00
Tiago Cunha
6694a01861 Sync OpenBSD patchset 698:
Catch SIGHUP and terminate if running as a client. This prevents clients
from being left hanging around when, for example, a SSH session is
disconnected.

ok nicm@
2010-05-14 14:35:26 +00:00
Tiago Cunha
9900e28ba8 Sync OpenBSD patchset 697:
Identical behaviour to select-prompt can now be obtained with
command-prompt, so remove select-prompt and change ' to be bound to
command-prompt -p index "select-window -t :%%".
2010-05-14 14:33:39 +00:00
Tiago Cunha
fc69b9ccb7 Sync OpenBSD patchset 696:
Make signal handler setup/teardown two common functions instead of six,
and reset SIGCHLD after fork to fix problems with some shells. From
Romain Francoise.
2010-05-14 14:30:01 +00:00
Tiago Cunha
d3dd6709bc Sync OpenBSD patchset 693:
Make C-] and other punctuation-based control key combinations work again.

ok nicm
2010-05-14 14:21:07 +00:00
Tiago Cunha
3cded44623 Sync OpenBSD patchset 692:
sort options.
2010-05-14 14:19:41 +00:00
Tiago Cunha
50cad52ae6 Sync OpenBSD patchset 691:
Make the active pane border have a green foreground instead of
background by default.
2010-05-14 14:18:54 +00:00
Tiago Cunha
701b5bdf61 Sync OpenBSD patchset 688:
Add a tiled layout, originally from Liam Bedford a while ago, fixed up
by me.
2010-05-14 14:16:37 +00:00
Nicholas Marriott
4e120c00f7 Use LC_ALL for sed too since apparently some platforms play silly games
in other locales.
2010-05-12 19:47:25 +00:00
Nicholas Marriott
7d4588f470 +. 2010-05-12 19:21:15 +00:00
Nicholas Marriott
893be14cf8 +. 2010-04-28 19:08:40 +00:00
Micah Cowan
342a47bc77 Avoid crashing in copy-mode during resize, when our history-viewing offset is larger than the new total number of history lines. 2010-04-28 14:29:27 +00:00
Nicholas Marriott
18ed37622e When converting A-Z into a control character, want to subtract 64 not
65... whoops.
2010-04-23 20:33:08 +00:00
Nicholas Marriott
ec56ec7920 Use INSTALL so people on Solaris can set it to ginstall. 2010-04-23 07:38:36 +00:00
Nicholas Marriott
0c5a964e63 Support NetBSD 6 which will now have its own terminfo (yay). 2010-04-23 07:29:39 +00:00
Tiago Cunha
c4c542efb9 Sync OpenBSD patchset 686:
Mark zombie windows as dead in choose-window list, from Romain Francoise.
2010-04-22 21:51:27 +00:00
Tiago Cunha
2bc150d16d Sync OpenBSD patchset 685:
Rewrite key string conversions to be readable and to work properly for
multiple modifiers.
2010-04-22 21:50:30 +00:00
Tiago Cunha
7163907ab6 Sync OpenBSD patchset 684:
Catch SIGCHLD to avoid a zombie, from patrick keshishian.
2010-04-22 21:48:49 +00:00
Nicholas Marriott
02fc1fe0da Done. 2010-04-21 21:35:07 +00:00
Nicholas Marriott
8e67b07489 Don't set user and group with install, from Nicolas Pinto. 2010-04-21 21:22:06 +00:00
Tiago Cunha
0ed80637e7 Sync OpenBSD patchset 683:
Fix typo in escape state table leading to fatal() when \033} or \033~
was entered, from Chris Johnsen.
2010-04-18 15:11:47 +00:00
Tiago Cunha
b03418fc6b Sync OpenBSD patchset 682:
If remain-on-exit is set, both the error callback and a SIGCHLD could
destroy the same pane (because the first one doesn't remove it from the
list of panes), causing the pane bufferevent to be freed twice. So don't
free it if the fd has already been set to -1, from Romain Francoise.
2010-04-18 15:10:55 +00:00
Nicholas Marriott
c0f03afbac +. 2010-04-18 07:37:09 +00:00
Tiago Cunha
0646b3caf2 Sync OpenBSD patchset 680:
Remove XXX comment and just close received fd if calloc() fails.

If this happens the imsg may no longer be usable as there may be queued
messages, but this is a) already the case with the code now, and b)
would be the case if recvmsg() fails anyway, so we can document that -1
from imsg_read() invalidates the struct imsgbuf.

discussed with and ok eric
2010-04-12 21:45:18 +00:00
Micah Cowan
b2e752b384 Don't try to use a window-link that may have been freed.
In the case where a join-pane is performed from within a grouped session,
and the source pane had no siblings in the window (causing the window to
be destroyed), there was an invalid access of the destination window
link (which had been destroyed as part of the group session's
resynchronization with the original session, due to killing the
now-empty source window).
CVS: ----------------------------------------------------------------------
CVS: Enter Log.  Lines beginning with `CVS:' are removed automatically
CVS:
CVS: Committing in .
CVS:
CVS: Modified Files:
CVS: 	cmd-join-pane.c
CVS: ----------------------------------------------------------------------
2010-04-09 07:09:37 +00:00
Nicholas Marriott
08632b4f0a there can be only one rpathbuf 2010-04-08 07:54:43 +00:00
Nicholas Marriott
10b73b7a11 Sync nit. 2010-04-06 22:08:10 +00:00
Nicholas Marriott
cd0f22b96e Unbreak. Whoops. 2010-04-06 22:02:52 +00:00
Nicholas Marriott
610056abbe Man page sync. 2010-04-06 22:02:03 +00:00
Nicholas Marriott
3743238a86 From Bob Beck:
rather than using an empty "" as the default window title, put the hostname
of the machine we are running on in there.

makes my many green lines easier to deal with without using fiddly options to
set it.
2010-04-06 22:01:32 +00:00
Nicholas Marriott
531db321e3 -s src-pane. 2010-04-06 21:59:59 +00:00
Nicholas Marriott
642f549e4d Dead assignment. 2010-04-06 21:59:37 +00:00
Nicholas Marriott
0fc65537a3 Run job commands explicitly in the global enviroment (which can be
modified with setenv -g) rather than with the environment tmux started
with.
2010-04-06 21:59:19 +00:00
Nicholas Marriott
091db41bc9 Squash a function that is only called in a callback into the
callback function.
2010-04-06 21:58:33 +00:00
Nicholas Marriott
67300e9524 Stupid style nits. 2010-04-06 21:45:36 +00:00
Nicholas Marriott
f2a4ef5260 window-more.c is now defunct. 2010-04-06 10:53:41 +00:00
Nicholas Marriott
7dc1720522 +. 2010-04-05 22:28:56 +00:00
Nicholas Marriott
07dcf8610f FreeBSD kqueue is broken before 8. 2010-04-05 22:28:25 +00:00
Micah Cowan
2d74ce1d3a Merge output (more) and copy modes into one single mode (called copy). 2010-04-05 05:11:44 +00:00
Nicholas Marriott
5879e2a32b libevent needs librt on Linux, from Aaron Isotton. 2010-04-02 21:26:40 +00:00
Nicholas Marriott
1392fba63d Don't accept keys with modifiers as input. Fixes crash reported by Brian
R Landy.
2010-03-31 18:24:08 +00:00
Nicholas Marriott
1c6ab725f5 +. 2010-03-29 18:54:07 +00:00
Nicholas Marriott
4012917302 Nuke unused functions. 2010-03-27 15:12:56 +00:00
Nicholas Marriott
dd7abd9b4c -a flag to insert a window after an existing one, moving other windows
up as necessary.
2010-03-27 15:12:11 +00:00
Nicholas Marriott
51c776fe93 +. 2010-03-27 13:43:13 +00:00
Nicholas Marriott
9382e546df +. 2010-03-18 21:10:11 +00:00
Nicholas Marriott
659d15786a Reset output functions too when changing client after attaching. 2010-03-18 21:06:40 +00:00
Nicholas Marriott
2307b91ecb paste-buffer should be per pane, from C. Coutinho. 2010-03-18 21:02:41 +00:00
Nicholas Marriott
a2c87eb899 Unused variable. 2010-03-16 23:40:14 +00:00
Nicholas Marriott
33a90efc93 Minor Nazi style tweaks to previous, and man page rephrasery. 2010-03-16 17:51:32 +00:00
Micah Cowan
009d8d2ea7 Jump-forward, jump-backward in copy mode, based on vi's F and f commands. 2010-03-16 17:30:58 +00:00
Nicholas Marriott
aa8f9018ea Support up, down, left, right movement through panes with -UDLR flags to
select-pane.

Also remove up- and down-pane: equivalent behaviour is now available
using -t :.+ and -t :.-.
2010-03-15 22:03:38 +00:00
Nicholas Marriott
4de04fac2c Accept a full key match (not a partial) even if there is data left in
the buffer.
2010-03-15 20:44:51 +00:00
Nicholas Marriott
593bcbdd49 +. 2010-03-15 16:09:49 +00:00
Nicholas Marriott
9f5b9ba0d6 New input parser based on http://vt100.net/emu/dec_ansi_parser. 2010-03-15 12:51:23 +00:00
Nicholas Marriott
b1a3090877 + an item. 2010-03-14 23:46:52 +00:00
Nicholas Marriott
4271320bb7 Quick prioritise for 1.3. 2010-03-14 23:46:09 +00:00
Nicholas Marriott
51eab54102 Avoid use-after-free when cancelling copy mode. 2010-03-14 23:17:59 +00:00
Nicholas Marriott
51c135ed73 +. 2010-03-10 23:32:49 +00:00
Nicholas Marriott
f6d36e60cf Mention dependencies. 2010-03-10 22:13:17 +00:00
Tiago Cunha
38bc7e87c5 Working on 1.3. 2010-03-10 15:44:13 +00:00
77 changed files with 4253 additions and 3011 deletions

48
CHANGES
View File

@@ -1,3 +1,49 @@
CHANGES FROM 1.2 TO 1.3, 18 July 2010
* New input parser.
* Flags to move through panes -UDLR added to select-pane.
* Commands up-pane, and down-pane removed, since equivalent behaviour is now
available through the target flag (-t:+ and -t:-).
* Jump-forward/backward in copy move (based on vi's F, and f commands).
* Make paste-buffer accept a pane as a target.
* Flag -a added to new-window to insert a window after an existing one, moving
windows up if necessary.
* Merge more mode into copy mode.
* Run job commands explicitly in the global environment (which can be modified
with setenv -g), rather than with the environment tmux started with.
* Use the machine's hostname as the default title, instead of an empty string.
* Prevent double free if the window option remain-on-exit is set.
* Key string conversions rewritten.
* Mark zombie windows as dead in the choose-window list.
* Tiled layout added.
* Signal handling reworked.
* Reset SIGCHLD after fork to fix problems with some shells.
* Select-prompt command removed. Therefore, bound ' to command-prompt -p index
"select-window -t:%%" by default.
* Catch SIGHUP and terminate if running as a client, thus avoiding clients from
being left hanging around when, for instance, a SSH session is disconnected.
* Solaris 9 fixes (such as adding compat {get,set}env(3) code).
* Accept none instead of default for attributes.
* Window options window-status-alert-{alert,bg,fg} added.
* Flag -s added to the paste-buffer command to specify a custom separator.
* Allow dragging to make a selection in copy mode if the mode-mouse option is
set.
* Support the mouse scroll wheel.
* Make pipe-pane accept special character sequences (eg #I).
* Fix problems with window sizing when starting tmux from .xinitrc.
* Give tmux sockets (but not the containing folder) group permissions.
* Extend the target flags (ie -t) to accept an offset (for example -t:+2), and
make it wrap windows, and panes.
* New command choose-buffer added.
* New server option detach-on-destroy to set what happens to a client when the
session it is attached to is destroyed. If on (default), the client is
detached. Otherwise, the client is switched to the most recently active of
the remaining sessions.
* The commands load-buffer, and save-buffer now accept a dash (-) as the file
to read from stdin, or write to stdout.
* Custom layouts added.
* Additional code reduction, bug fixes, and manpage enhancements.
CHANGES FROM 1.1 TO 1.2, 10 March 2010
* Switch to libevent.
@@ -1467,7 +1513,7 @@ The list of older changes is below.
(including mutt, emacs). No status bar yet and no key remapping or other
customisation.
$Id: CHANGES,v 1.302 2010-03-10 15:18:11 tcunha Exp $
$Id: CHANGES,v 1.303 2010-07-18 13:40:59 tcunha Exp $
LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr
LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms

View File

@@ -1,4 +1,4 @@
# $Id: GNUmakefile,v 1.122 2010-03-10 15:15:33 tcunha Exp $
# $Id: GNUmakefile,v 1.128 2010-07-18 13:36:52 tcunha Exp $
#
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
#
@@ -17,7 +17,7 @@
.PHONY: clean
VERSION= 1.2
VERSION= 1.3
#FDEBUG= 1
@@ -28,7 +28,7 @@ LIBS+=
# Sun CC
ifneq ($(shell ($(CC) -V 2>&1|awk '/Sun C/' || true)), )
CFLAGS+=-erroff=E_EMPTY_DECLARATION
CFLAGS+= -erroff=E_EMPTY_DECLARATION
FDEBUG=
endif
@@ -52,11 +52,12 @@ endif
endif
PREFIX?= /usr/local
INSTALLDIR= install -d
INSTALLBIN= install -g bin -o root -m 555
INSTALLMAN= install -g bin -o root -m 444
INSTALL?= install
INSTALLDIR= $(INSTALL) -d
INSTALLBIN= $(INSTALL) -m 555
INSTALLMAN= $(INSTALL) -m 444
SRCS= $(shell echo *.c|sed 's|osdep-[a-z0-9]*.c||g')
SRCS= $(shell echo *.c|LC_ALL=C sed 's|osdep-[a-z0-9]*.c||g')
include config.mk
OBJS= $(patsubst %.c,%.o,$(SRCS))

View File

@@ -1,4 +1,4 @@
# $Id: Makefile,v 1.155 2010-03-10 15:15:33 tcunha Exp $
# $Id: Makefile,v 1.160 2010-07-18 13:36:52 tcunha Exp $
#
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
#
@@ -18,7 +18,7 @@
.SUFFIXES: .c .o
.PHONY: clean
VERSION= 1.2
VERSION= 1.3
#FDEBUG= 1
@@ -48,11 +48,12 @@ CFLAGS+= -Wno-pointer-sign
.endif
PREFIX?= /usr/local
INSTALLDIR= install -d
INSTALLBIN= install -g bin -o root -m 555
INSTALLMAN= install -g bin -o root -m 444
INSTALL?= install
INSTALLDIR= ${INSTALL} -d
INSTALLBIN= ${INSTALL} -m 555
INSTALLMAN= ${INSTALL} -m 444
SRCS!= echo *.c|sed 's|osdep-[a-z0-9]*.c||g'
SRCS!= echo *.c|LC_ALL=C sed 's|osdep-[a-z0-9]*.c||g'
.include "config.mk"
OBJS= ${SRCS:S/.c/.o/}

45
TODO
View File

@@ -15,7 +15,6 @@
session not being watched?
- next prev word etc in command prompt
- many more info() displays for various things
- input.c is too complicated. simplify?
- use a better termcap internally instead of screen, perhaps xterm
- fix rxvt cursor fg issue (text under cursor can have non-white fg)
- should be able to move to a hidden pane and it would be moved into view. pane
@@ -90,8 +89,6 @@
message display
copy and paste cursor and wide characters
...?
- option so that when session is destroyed, attach client to another session
rather than exiting
- session history for client and last-session command
- option to change status line colour when current window is in a mode?
- option to move copy mode indicator into status line
@@ -100,12 +97,10 @@
- live update: server started with -U connects to server, requests sessions and
windows, receives fds
- convert status line history to be server global (anything else?)
- something for -t "last window in session" so a session can be used as a stack
- command to show a tree of sessions-windows-panes (active marked with *)
- sort out inheriting config from shell on new sessions/windows:
should pick up default-path/termios/etc from client if possible,
else leave empty/default
- define custom layouts
- link panes into multiple windows
- -h option to capture-pane to capture the history as well
- bells should be passed between sessions with visual-bell etc
@@ -118,18 +113,40 @@
- multiline status line
- flag for absolute pane size to resize-pane
- sanity check input to socket
- stdin fd should be passed up to parent so load-buffer and others could use it
for nonattaching clients
- environment should be set up for jobs
- select-buffer command
- fix jobs so they block in config file rather than executing at an arbitrary
future point -- need state stored in client so other clients can proceed
- rectangle copy:
when selecting leftward, cursor should be inside block per emacs
key to rotate corner at which cursor is
- double C-a should walk back over wrapped lines like C-e
- support title stack, both internally and externally
http://docs.freebsd.org/cgi/getmsg.cgi?fetch=1149299+0+archive/2010/freebsd-questions/20100207.freebsd-questions
- copy buffers should be global, limit can be server option, nuke copy-buffer
command
- command to show status line information briefly when it is off
- some way to pad # stuff with spaces, #!2T maybe
- FreeBSD console problems
- a binding to "scroll down and exit at bottom" copy mode
- some way to pass keystrokes in copy mode through to underlying window
- last window update time and # replacement for it for display-message
- find-window across sessions - other ways to make session handling easier?
- ' and " should be parsed the same (eg "\e" vs '\e') in config and command
prompt?
- command to toggle selection not to move it in copy-mode
For 1.3 (not in order):
3 why are alerts per-winlink? try per window?
4 audit of escape sequence support vs xterm
6 rectangle copy: when selecting leftward, cursor should be inside block per
emacs key to rotate corner at which cursor is
9 something for -t "last window in session" so a session can be used as a stack
10 synchronous commands - client sends cmd and blocks, neww/splitw saves client
ptr then when program inside died, sends MSG_SOMETHING with wait status to
client
11 documentation improvements - rlpowell's tutorial
- build instructions
12 better configure? with-libevent
14 bind commands to key sequences?
16 monitor, bell etc should monitor /all/ panes in the window not just one
17 wd should be updated on attach etc. maybe lose default-path and use PWD
18 a history of commands that can be reversed (reverse member of each command, and a buffer)
19 info() when changing to same window
20 don't pass UTF-8 through vis for titles
...

View File

@@ -1,4 +1,4 @@
/* $Id: array.h,v 1.10 2010-02-08 18:29:32 tcunha Exp $ */
/* $Id: array.h,v 1.11 2010-06-06 00:27:08 tcunha Exp $ */
/*
* Copyright (c) 2006 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -47,7 +47,7 @@
} \
} while (0)
#define ARRAY_EMPTY(a) ((a) == NULL || (a)->num == 0)
#define ARRAY_EMPTY(a) (((void *) (a)) == NULL || (a)->num == 0)
#define ARRAY_LENGTH(a) ((a)->num)
#define ARRAY_DATA(a) ((a)->list)

View File

@@ -1,4 +1,4 @@
/* $Id: attributes.c,v 1.3 2009-11-28 14:46:23 tcunha Exp $ */
/* $Id: attributes.c,v 1.4 2010-06-05 23:54:51 tcunha Exp $ */
/*
* Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org>
@@ -28,7 +28,7 @@ attributes_tostring(u_char attr)
static char buf[128];
if (attr == 0)
return ("default");
return ("none");
buf[0] = '\0';
if (attr & GRID_ATTR_BRIGHT)
@@ -63,7 +63,7 @@ attributes_fromstring(const char *str)
if (strchr(delimiters, str[strlen(str) - 1]) != NULL)
return (-1);
if (strcasecmp(str, "default") == 0)
if (strcasecmp(str, "default") == 0 || strcasecmp(str, "none") == 0)
return (0);
attr = 0;

4
cfg.c
View File

@@ -1,4 +1,4 @@
/* $Id: cfg.c,v 1.26 2010-02-08 18:29:32 tcunha Exp $ */
/* $Id: cfg.c,v 1.27 2010-06-06 00:04:18 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -69,7 +69,7 @@ cfg_add_cause(struct causelist *causes, const char *fmt, ...)
/*
* Load configuration file. Returns -1 for an error with a list of messages in
* causes. Note that causes and ncauses must be initialised by the caller!
* causes. Note that causes must be initialised by the caller!
*/
int
load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)

View File

@@ -1,4 +1,4 @@
/* $Id: client.c,v 1.90 2009-12-04 22:14:47 tcunha Exp $ */
/* $Id: client.c,v 1.95 2010-07-02 02:52:13 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -17,7 +17,6 @@
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
@@ -101,8 +100,7 @@ server_started:
if (cmdflags & CMD_SENDENVIRON)
client_send_environ();
if (isatty(STDIN_FILENO))
client_send_identify(flags);
client_send_identify(flags);
return (&client_ibuf);
@@ -119,12 +117,9 @@ void
client_send_identify(int flags)
{
struct msg_identify_data data;
struct winsize ws;
char *term;
int fd;
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl(TIOCGWINSZ)");
data.flags = flags;
if (getcwd(data.cwd, sizeof data.cwd) == NULL)
@@ -139,6 +134,14 @@ client_send_identify(int flags)
fatal("dup failed");
imsg_compose(&client_ibuf,
MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
if ((fd = dup(STDOUT_FILENO)) == -1)
fatal("dup failed");
imsg_compose(&client_ibuf, MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0);
if ((fd = dup(STDERR_FILENO)) == -1)
fatal("dup failed");
imsg_compose(&client_ibuf, MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0);
}
void
@@ -176,35 +179,19 @@ client_update_event(void)
__dead void
client_main(void)
{
struct event ev_sigcont, ev_sigterm, ev_sigwinch;
struct sigaction sigact;
logfile("client");
/* Note: event_init() has already been called. */
/* Set up signals. */
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
set_signals(client_signal);
signal_set(&ev_sigcont, SIGCONT, client_signal, NULL);
signal_add(&ev_sigcont, NULL);
signal_set(&ev_sigterm, SIGTERM, client_signal, NULL);
signal_add(&ev_sigterm, NULL);
signal_set(&ev_sigwinch, SIGWINCH, client_signal, NULL);
signal_add(&ev_sigwinch, NULL);
/*
* Send a resize message immediately in case the terminal size has
* changed between the identify message to the server and the MSG_READY
* telling us to move into the client code.
*/
client_write_server(MSG_RESIZE, NULL, 0);
/*
* imsg_read in the first client poll loop (before the terminal has
@@ -233,6 +220,11 @@ client_signal(int sig, unused short events, unused void *data)
struct sigaction sigact;
switch (sig) {
case SIGHUP:
client_exitmsg = "lost tty";
client_exitval = 1;
client_write_server(MSG_EXITING, NULL, 0);
break;
case SIGTERM:
client_exitmsg = "terminated";
client_exitval = 1;

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-bind-key.c,v 1.28 2010-01-25 17:12:44 tcunha Exp $ */
/* $Id: cmd-bind-key.c,v 1.29 2010-07-02 02:43:01 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -130,7 +130,7 @@ cmd_bind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
return (cmd_bind_key_table(self, ctx));
key_bindings_add(data->key, data->can_repeat, data->cmdlist);
data->cmdlist = NULL; /* avoid free */
data->cmdlist->references++;
return (0);
}
@@ -192,8 +192,17 @@ cmd_bind_key_print(struct cmd *self, char *buf, size_t len)
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->command_key)
off += xsnprintf(buf + off, len - off, " -c");
if (off < len && !(data->key & KEYC_PREFIX))
off += xsnprintf(buf + off, len - off, " -n");
if (off < len && data->can_repeat)
off += xsnprintf(buf + off, len - off, " -r");
if (off < len && data->tablename != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->tablename);
if (off < len) {
skey = key_string_lookup_key(data->key);
skey = key_string_lookup_key(data->key & ~KEYC_PREFIX);
off += xsnprintf(buf + off, len - off, " %s ", skey);
}
if (off < len)

146
cmd-choose-buffer.c Normal file
View File

@@ -0,0 +1,146 @@
/* $Id: cmd-choose-buffer.c,v 1.1 2010-06-22 23:35:20 tcunha Exp $ */
/*
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include "tmux.h"
/*
* Enter choice mode to choose a buffer.
*/
int cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_choose_buffer_callback(void *, int);
void cmd_choose_buffer_free(void *);
const struct cmd_entry cmd_choose_buffer_entry = {
"choose-buffer", NULL,
CMD_TARGET_WINDOW_USAGE " [template]",
CMD_ARG01, "",
cmd_target_init,
cmd_target_parse,
cmd_choose_buffer_exec,
cmd_target_free,
cmd_target_print
};
struct cmd_choose_buffer_data {
struct client *client;
char *template;
};
int
cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct cmd_choose_buffer_data *cdata;
struct session *s;
struct winlink *wl;
struct paste_buffer *pb;
u_int idx;
char *tmp;
if (ctx->curclient == NULL) {
ctx->error(ctx, "must be run interactively");
return (-1);
}
s = ctx->curclient->session;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (paste_get_top(&s->buffers) == NULL)
return (0);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (0);
idx = 0;
while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) {
tmp = paste_print(pb, 50);
window_choose_add(wl->window->active, idx - 1,
"%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp);
xfree(tmp);
}
cdata = xmalloc(sizeof *cdata);
if (data->arg != NULL)
cdata->template = xstrdup(data->arg);
else
cdata->template = xstrdup("paste-buffer -b '%%'");
cdata->client = ctx->curclient;
cdata->client->references++;
window_choose_ready(wl->window->active,
0, cmd_choose_buffer_callback, cmd_choose_buffer_free, cdata);
return (0);
}
void
cmd_choose_buffer_callback(void *data, int idx)
{
struct cmd_choose_buffer_data *cdata = data;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *template, *cause, tmp[16];
if (idx == -1)
return;
if (cdata->client->flags & CLIENT_DEAD)
return;
xsnprintf(tmp, sizeof tmp, "%u", idx);
template = cmd_template_replace(cdata->template, tmp, 1);
if (cmd_string_parse(template, &cmdlist, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(cdata->client, "%s", cause);
xfree(cause);
}
xfree(template);
return;
}
xfree(template);
ctx.msgdata = NULL;
ctx.curclient = cdata->client;
ctx.error = key_bindings_error;
ctx.print = key_bindings_print;
ctx.info = key_bindings_info;
ctx.cmdclient = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
}
void
cmd_choose_buffer_free(void *data)
{
struct cmd_choose_buffer_data *cdata = data;
cdata->client->references--;
xfree(cdata->template);
xfree(cdata);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-choose-window.c,v 1.20 2009-12-04 22:14:47 tcunha Exp $ */
/* $Id: cmd-choose-window.c,v 1.22 2010-06-22 23:26:18 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -81,11 +81,11 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
idx++;
flag = ' ';
if (session_alert_has(s, wm, WINDOW_ACTIVITY))
if (wm->flags & WINLINK_ACTIVITY)
flag = '#';
else if (session_alert_has(s, wm, WINDOW_BELL))
else if (wm->flags & WINLINK_BELL)
flag = '!';
else if (session_alert_has(s, wm, WINDOW_CONTENT))
else if (wm->flags & WINLINK_CONTENT)
flag = '+';
else if (wm == s->curw)
flag = '*';
@@ -101,8 +101,9 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
left = right = "";
window_choose_add(wl->window->active,
wm->idx, "%3d: %s%c [%ux%u] (%u panes)%s%s%s",
wm->idx, "%3d: %s%c [%ux%u] (%u panes%s)%s%s%s",
wm->idx, w->name, flag, w->sx, w->sy, window_count_panes(w),
w->active->fd == -1 ? ", dead" : "",
left, title, right);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-command-prompt.c,v 1.27 2009-11-14 17:56:39 tcunha Exp $ */
/* $Id: cmd-command-prompt.c,v 1.28 2010-05-14 14:33:39 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -81,6 +81,10 @@ cmd_command_prompt_init(struct cmd *self, int key)
case 'f':
data->template = xstrdup("find-window '%%'");
break;
case '\'':
data->template = xstrdup("select-window -t ':%%'");
data->prompts = xstrdup("index");
break;
}
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-copy-mode.c,v 1.26 2010-01-05 23:50:22 tcunha Exp $ */
/* $Id: cmd-copy-mode.c,v 1.27 2010-04-05 05:11:42 micahcowan Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -63,6 +63,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1);
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_from_pane(wp);
if (wp->mode == &window_copy_mode && cmd_check_flag(data->chflags, 'u'))
window_copy_pageup(wp);

View File

@@ -1,60 +0,0 @@
/* $Id: cmd-down-pane.c,v 1.14 2010-01-05 23:52:37 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* 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"
/*
* Move down a pane.
*/
int cmd_down_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_down_pane_entry = {
"down-pane", "downp",
CMD_TARGET_WINDOW_USAGE,
0, "",
cmd_target_init,
cmd_target_parse,
cmd_down_pane_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_down_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct window *w;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
w = wl->window;
do {
w->active = TAILQ_NEXT(w->active, entry);
if (w->active == NULL)
w->active = TAILQ_FIRST(&w->panes);
} while (!window_pane_visible(w->active));
server_status_window(wl->window);
server_redraw_window_borders(wl->window);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-if-shell.c,v 1.8 2009-11-14 17:56:39 tcunha Exp $ */
/* $Id: cmd-if-shell.c,v 1.9 2010-07-17 14:36:40 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -104,10 +104,13 @@ cmd_if_shell_free(void *data)
{
struct cmd_if_shell_data *cdata = data;
struct cmd_ctx *ctx = &cdata->ctx;
struct msg_exit_data exitdata;
if (ctx->cmdclient != NULL) {
ctx->cmdclient->references--;
server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0);
exitdata.retcode = ctx->cmdclient->retcode;
server_write_client(
ctx->cmdclient, MSG_EXIT, &exitdata, sizeof exitdata);
}
if (ctx->curclient != NULL)
ctx->curclient->references--;

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-join-pane.c,v 1.2 2010-01-08 16:34:17 tcunha Exp $ */
/* $Id: cmd-join-pane.c,v 1.4 2010-04-09 07:09:37 micahcowan Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -44,7 +44,7 @@ struct cmd_join_pane_data {
const struct cmd_entry cmd_join_pane_entry = {
"join-pane", "joinp",
"[-dhv] [-p percentage|-l size] [-t src-pane] [-t dst-pane] [command]",
"[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane] [command]",
0, "",
cmd_join_pane_init,
cmd_join_pane_parse,
@@ -150,13 +150,14 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w;
struct window_pane *src_wp, *dst_wp;
int size;
int size, dst_idx;
enum layout_type type;
struct layout_cell *lc;
if ((dst_wl = cmd_find_pane(ctx, data->dst, &dst_s, &dst_wp)) == NULL)
return (-1);
dst_w = dst_wl->window;
dst_idx = dst_wl->idx;
if ((src_wl = cmd_find_pane(ctx, data->src, NULL, &src_wp)) == NULL)
return (-1);
@@ -209,7 +210,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
if (!data->flag_detached) {
window_set_active_pane(dst_w, src_wp);
session_select(dst_s, dst_wl->idx);
session_select(dst_s, dst_idx);
server_redraw_session(dst_s);
} else
server_status_session(dst_s);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-kill-session.c,v 1.17 2009-12-04 22:14:47 tcunha Exp $ */
/* $Id: cmd-kill-session.c,v 1.18 2010-07-02 02:43:50 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -45,21 +45,11 @@ cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct session *s;
struct client *c;
u_int i;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL && c->session == s) {
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
}
}
recalculate_sizes();
server_destroy_session(s);
session_destroy(s);
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list-buffers.c,v 1.15 2009-12-04 22:14:47 tcunha Exp $ */
/* $Id: cmd-list-buffers.c,v 1.16 2010-06-22 23:35:20 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -46,32 +46,17 @@ cmd_list_buffers_exec(struct cmd *self, struct cmd_ctx *ctx)
struct session *s;
struct paste_buffer *pb;
u_int idx;
char tmp[51 * 4 + 1];
size_t size, len;
char *tmp;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
idx = 0;
while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) {
size = pb->size;
/* Translate the first 50 characters. */
len = size;
if (len > 50)
len = 50;
strvisx(tmp, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL);
/*
* If the first 50 characters were encoded as a longer string,
* or there is definitely more data, add "...".
*/
if (size > 50 || strlen(tmp) > 50) {
tmp[50 - 3] = '\0';
strlcat(tmp, "...", sizeof tmp);
}
ctx->print(ctx, "%u: %zu bytes: \"%s\"", idx - 1, size, tmp);
tmp = paste_print(pb, 50);
ctx->print(ctx,
"%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp);
xfree(tmp);
}
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list-windows.c,v 1.42 2009-11-14 17:56:39 tcunha Exp $ */
/* $Id: cmd-list-windows.c,v 1.43 2010-07-02 02:54:52 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -45,6 +45,7 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_target_data *data = self->data;
struct session *s;
struct winlink *wl;
char *layout;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
@@ -52,6 +53,9 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
RB_FOREACH(wl, winlinks, &s->windows) {
ctx->print(ctx, "%d: %s [%ux%u]",
wl->idx, wl->window->name, wl->window->sx, wl->window->sy);
layout = layout_dump(wl->window);
ctx->print(ctx, " layout: %s", layout);
xfree(layout);
}
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list.c,v 1.7 2010-02-02 23:51:04 tcunha Exp $ */
/* $Id: cmd-list.c,v 1.9 2010-07-02 02:43:01 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -32,7 +32,8 @@ cmd_list_parse(int argc, char **argv, char **cause)
char **new_argv;
cmdlist = xmalloc(sizeof *cmdlist);
TAILQ_INIT(cmdlist);
cmdlist->references = 1;
TAILQ_INIT(&cmdlist->list);
lastsplit = 0;
for (i = 0; i < argc; i++) {
@@ -54,7 +55,7 @@ cmd_list_parse(int argc, char **argv, char **cause)
cmd = cmd_parse(new_argc, new_argv, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(cmdlist, cmd, qentry);
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
lastsplit = i + 1;
}
@@ -63,7 +64,7 @@ cmd_list_parse(int argc, char **argv, char **cause)
cmd = cmd_parse(argc - lastsplit, argv + lastsplit, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(cmdlist, cmd, qentry);
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
}
return (cmdlist);
@@ -80,7 +81,7 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
int n, retval;
retval = 0;
TAILQ_FOREACH(cmd, cmdlist, qentry) {
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if ((n = cmd_exec(cmd, ctx)) == -1)
return (-1);
@@ -99,6 +100,10 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
if (ctx->curclient == NULL) {
ctx->curclient = ctx->cmdclient;
ctx->cmdclient = NULL;
ctx->error = key_bindings_error;
ctx->print = key_bindings_print;
ctx->info = key_bindings_info;
}
}
}
@@ -110,9 +115,12 @@ cmd_list_free(struct cmd_list *cmdlist)
{
struct cmd *cmd;
while (!TAILQ_EMPTY(cmdlist)) {
cmd = TAILQ_FIRST(cmdlist);
TAILQ_REMOVE(cmdlist, cmd, qentry);
if (--cmdlist->references != 0)
return;
while (!TAILQ_EMPTY(&cmdlist->list)) {
cmd = TAILQ_FIRST(&cmdlist->list);
TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
cmd_free(cmd);
}
xfree(cmdlist);
@@ -125,7 +133,7 @@ cmd_list_print(struct cmd_list *cmdlist, char *buf, size_t len)
size_t off;
off = 0;
TAILQ_FOREACH(cmd, cmdlist, qentry) {
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if (off >= len)
break;
off += cmd_print(cmd, buf + off, len - off);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-load-buffer.c,v 1.15 2010-02-26 13:30:07 tcunha Exp $ */
/* $Id: cmd-load-buffer.c,v 1.16 2010-07-02 02:52:13 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -16,10 +16,13 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
@@ -45,7 +48,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_buffer_data *data = self->data;
struct session *s;
FILE *f;
FILE *f, *close_f;
char *pdata, *new_pdata;
size_t psize;
u_int limit;
@@ -54,9 +57,23 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if ((f = fopen(data->arg, "rb")) == NULL) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
if (strcmp(data->arg, "-") == 0 ) {
if (ctx->cmdclient == NULL) {
ctx->error(ctx, "%s: can't read from stdin", data->arg);
return (-1);
}
f = ctx->cmdclient->stdin_file;
if (isatty(fileno(ctx->cmdclient->stdin_file))) {
ctx->error(ctx, "%s: stdin is a tty", data->arg);
return (-1);
}
close_f = NULL;
} else {
if ((f = fopen(data->arg, "rb")) == NULL) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
}
close_f = f;
}
pdata = NULL;
@@ -77,7 +94,8 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
if (pdata != NULL)
pdata[psize] = '\0';
fclose(f);
if (close_f != NULL)
fclose(close_f);
limit = options_get_number(&s->options, "buffer-limit");
if (data->buffer == -1) {
@@ -94,6 +112,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
error:
if (pdata != NULL)
xfree(pdata);
fclose(f);
if (close_f != NULL)
fclose(close_f);
return (-1);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-new-session.c,v 1.76 2010-02-26 13:28:15 tcunha Exp $ */
/* $Id: cmd-new-session.c,v 1.78 2010-07-02 02:49:19 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,8 +18,10 @@
#include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "tmux.h"
@@ -125,8 +127,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
struct window_pane *wp;
struct environ env;
struct termios tio, *tiop;
const char *update;
char *overrides, *cmd, *cwd, *cause;
struct passwd *pw;
const char *update, *cwd;
char *overrides, *cmd, *cause;
int detached, idx;
u_int sx, sy, i;
@@ -198,8 +201,13 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
/* Get the new session working directory. */
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
cwd = ctx->cmdclient->cwd;
else
cwd = options_get_string(&global_s_options, "default-path");
else {
pw = getpwuid(getuid());
if (pw->pw_dir != NULL && *pw->pw_dir != '\0')
cwd = pw->pw_dir;
else
cwd = "/";
}
/* Find new session size. */
if (detached) {
@@ -287,10 +295,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
*/
if (cfg_finished && !ARRAY_EMPTY(&cfg_causes)) {
wp = s->curw->window->active;
window_pane_set_mode(wp, &window_more_mode);
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp);
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
cause = ARRAY_ITEM(&cfg_causes, i);
window_more_add(wp, "%s", cause);
window_copy_add(wp, "%s", cause);
xfree(cause);
}
ARRAY_FREE(&cfg_causes);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-new-window.c,v 1.43 2010-01-22 17:28:34 tcunha Exp $ */
/* $Id: cmd-new-window.c,v 1.47 2010-07-02 02:49:19 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -36,13 +36,14 @@ struct cmd_new_window_data {
char *target;
char *name;
char *cmd;
int flag_insert_after;
int flag_detached;
int flag_kill;
};
const struct cmd_entry cmd_new_window_entry = {
"new-window", "neww",
"[-dk] [-n window-name] [-t target-window] [command]",
"[-adk] [-n window-name] [-t target-window] [command]",
0, "",
cmd_new_window_init,
cmd_new_window_parse,
@@ -61,6 +62,7 @@ cmd_new_window_init(struct cmd *self, unused int arg)
data->target = NULL;
data->name = NULL;
data->cmd = NULL;
data->flag_insert_after = 0;
data->flag_detached = 0;
data->flag_kill = 0;
}
@@ -74,8 +76,11 @@ cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause)
self->entry->init(self, KEYC_NONE);
data = self->data;
while ((opt = getopt(argc, argv, "dkt:n:")) != -1) {
while ((opt = getopt(argc, argv, "adkt:n:")) != -1) {
switch (opt) {
case 'a':
data->flag_insert_after = 1;
break;
case 'd':
data->flag_detached = 1;
break;
@@ -118,13 +123,36 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
struct session *s;
struct winlink *wl;
char *cmd, *cwd, *cause;
int idx;
int idx, last;
if (data == NULL)
return (0);
if ((idx = cmd_find_index(ctx, data->target, &s)) == -2)
return (-1);
if (data->flag_insert_after) {
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
idx = wl->idx + 1;
/* Find the next free index. */
for (last = idx; last < INT_MAX; last++) {
if (winlink_find_by_index(&s->windows, last) == NULL)
break;
}
if (last == INT_MAX) {
ctx->error(ctx, "no free window indexes");
return (-1);
}
/* Move everything from last - 1 to idx up a bit. */
for (; last > idx; last--) {
wl = winlink_find_by_index(&s->windows, last - 1);
server_link_window(s, wl, s, last, 0, 0, NULL);
server_unlink_window(s, wl);
}
} else {
if ((idx = cmd_find_index(ctx, data->target, &s)) == -2)
return (-1);
}
wl = NULL;
if (idx != -1)
@@ -134,7 +162,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
* Can't use session_detach as it will destroy session if this
* makes it empty.
*/
session_alert_cancel(s, wl);
wl->flags &= ~WINLINK_ALERTFLAGS;
winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl);
@@ -148,10 +176,13 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
cmd = data->cmd;
if (cmd == NULL)
cmd = options_get_string(&s->options, "default-command");
if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL)
cwd = options_get_string(&s->options, "default-path");
else
cwd = ctx->cmdclient->cwd;
cwd = options_get_string(&s->options, "default-path");
if (*cwd == '\0') {
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
cwd = ctx->cmdclient->cwd;
else
cwd = s->cwd;
}
if (idx == -1)
idx = -1 - options_get_number(&s->options, "base-index");

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-paste-buffer.c,v 1.24 2009-12-04 22:14:47 tcunha Exp $ */
/* $Id: cmd-paste-buffer.c,v 1.28 2010-06-06 00:03:02 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -26,32 +27,112 @@
* Paste paste buffer if present.
*/
struct cmd_paste_buffer_data {
char *target;
int buffer;
int flag_delete;
char *sepstr;
};
void cmd_paste_buffer_init(struct cmd *, int);
int cmd_paste_buffer_parse(struct cmd *, int, char **, char **);
int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_paste_buffer_lf2cr(struct window_pane *, const char *, size_t);
void cmd_paste_buffer_filter(
struct window_pane *, const char *, size_t, char *);
void cmd_paste_buffer_free(struct cmd *);
size_t cmd_paste_buffer_print(struct cmd *, char *, size_t);
const struct cmd_entry cmd_paste_buffer_entry = {
"paste-buffer", "pasteb",
"[-dr] " CMD_BUFFER_WINDOW_USAGE,
0, "dr",
cmd_buffer_init,
cmd_buffer_parse,
"[-dr] [-s separator] [-b buffer-index] [-t target-window]",
0, "",
cmd_paste_buffer_init,
cmd_paste_buffer_parse,
cmd_paste_buffer_exec,
cmd_buffer_free,
cmd_buffer_print
cmd_paste_buffer_free,
cmd_paste_buffer_print
};
/* ARGSUSED */
void
cmd_paste_buffer_init(struct cmd *self, unused int arg)
{
struct cmd_paste_buffer_data *data;
self->data = data = xmalloc(sizeof *data);
data->target = NULL;
data->buffer = -1;
data->flag_delete = 0;
data->sepstr = xstrdup("\r");
}
int
cmd_paste_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_paste_buffer_data *data;
int opt, n;
const char *errstr;
cmd_paste_buffer_init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "b:ds:t:r")) != -1) {
switch (opt) {
case 'b':
if (data->buffer == -1) {
n = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr != NULL) {
xasprintf(cause, "buffer %s", errstr);
goto error;
}
data->buffer = n;
}
break;
case 'd':
data->flag_delete = 1;
break;
case 's':
if (data->sepstr != NULL)
xfree(data->sepstr);
data->sepstr = xstrdup(optarg);
break;
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
case 'r':
if (data->sepstr != NULL)
xfree(data->sepstr);
data->sepstr = xstrdup("\n");
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
error:
self->entry->free(self);
return (-1);
}
int
cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_buffer_data *data = self->data;
struct winlink *wl;
struct window_pane *wp;
struct session *s;
struct paste_buffer *pb;
struct cmd_paste_buffer_data *data = self->data;
struct window_pane *wp;
struct session *s;
struct paste_buffer *pb;
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL)
return (-1);
wp = wl->window->active;
if (data->buffer == -1)
pb = paste_get_top(&s->buffers);
@@ -62,16 +143,11 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
}
}
if (pb != NULL) {
/* -r means raw data without LF->CR conversion. */
if (cmd_check_flag(data->chflags, 'r'))
bufferevent_write(wp->event, pb->data, pb->size);
else
cmd_paste_buffer_lf2cr(wp, pb->data, pb->size);
}
if (pb != NULL)
cmd_paste_buffer_filter(wp, pb->data, pb->size, data->sepstr);
/* Delete the buffer if -d. */
if (cmd_check_flag(data->chflags, 'd')) {
if (data->flag_delete) {
if (data->buffer == -1)
paste_free_top(&s->buffers);
else
@@ -81,20 +157,66 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
return (0);
}
/* Add bytes to a buffer but change every '\n' to '\r'. */
/* Add bytes to a buffer and filter '\n' according to separator. */
void
cmd_paste_buffer_lf2cr(struct window_pane *wp, const char *data, size_t size)
cmd_paste_buffer_filter(
struct window_pane *wp, const char *data, size_t size, char *sep)
{
const char *end = data + size;
const char *lf;
size_t seplen;
seplen = strlen(sep);
while ((lf = memchr(data, '\n', end - data)) != NULL) {
if (lf != data)
bufferevent_write(wp->event, data, lf - data);
bufferevent_write(wp->event, "\r", 1);
bufferevent_write(wp->event, sep, seplen);
data = lf + 1;
}
if (end != data)
bufferevent_write(wp->event, data, end - data);
}
void
cmd_paste_buffer_free(struct cmd *self)
{
struct cmd_paste_buffer_data *data = self->data;
if (data->target != NULL)
xfree(data->target);
if (data->sepstr != NULL)
xfree(data->sepstr);
xfree(data);
}
size_t
cmd_paste_buffer_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_paste_buffer_data *data = self->data;
size_t off = 0;
char tmp[BUFSIZ];
int r_flag;
r_flag = 0;
if (data->sepstr != NULL)
r_flag = (data->sepstr[0] == '\n' && data->sepstr[1] == '\0');
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->flag_delete)
off += xsnprintf(buf + off, len - off, " -d");
if (off < len && r_flag)
off += xsnprintf(buf + off, len - off, " -r");
if (off < len && data->buffer != -1)
off += xsnprintf(buf + off, len - off, " -b %d", data->buffer);
if (off < len && data->sepstr != NULL && !r_flag) {
strnvis(
tmp, data->sepstr, sizeof tmp, VIS_OCTAL|VIS_TAB|VIS_NL);
off += cmd_prarg(buf + off, len - off, " -s ", tmp);
}
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
return (off);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-pipe-pane.c,v 1.10 2009-12-04 22:14:47 tcunha Exp $ */
/* $Id: cmd-pipe-pane.c,v 1.13 2010-06-15 20:25:40 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -22,6 +22,7 @@
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "tmux.h"
@@ -49,9 +50,14 @@ int
cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct client *c;
struct window_pane *wp;
char *command;
int old_fd, pipe_fd[2], null_fd, mode;
if ((c = cmd_find_client(ctx, NULL)) == NULL)
return (-1);
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1);
@@ -90,7 +96,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
case 0:
/* Child process. */
close(pipe_fd[0]);
server_signal_clear();
clear_signals();
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
_exit(1);
@@ -105,7 +111,8 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO)
close(null_fd);
execl(_PATH_BSHELL, "sh", "-c", data->arg, (char *) NULL);
command = status_replace(c, NULL, data->arg, time(NULL), 0);
execl(_PATH_BSHELL, "sh", "-c", command, (char *) NULL);
_exit(1);
default:
/* Parent process. */

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-run-shell.c,v 1.6 2009-11-14 17:56:39 tcunha Exp $ */
/* $Id: cmd-run-shell.c,v 1.8 2010-07-17 14:36:40 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -82,6 +82,11 @@ cmd_run_shell_callback(struct job *job)
int retcode;
u_int lines;
if (ctx->cmdclient != NULL && ctx->cmdclient->flags & CLIENT_DEAD)
return;
if (ctx->curclient != NULL && ctx->curclient->flags & CLIENT_DEAD)
return;
lines = 0;
do {
if ((line = evbuffer_readline(job->event->input)) != NULL) {
@@ -126,10 +131,13 @@ cmd_run_shell_free(void *data)
{
struct cmd_run_shell_data *cdata = data;
struct cmd_ctx *ctx = &cdata->ctx;
struct msg_exit_data exitdata;
if (ctx->cmdclient != NULL) {
ctx->cmdclient->references--;
server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0);
exitdata.retcode = ctx->cmdclient->retcode;
server_write_client(
ctx->cmdclient, MSG_EXIT, &exitdata, sizeof exitdata);
}
if (ctx->curclient != NULL)
ctx->curclient->references--;

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-save-buffer.c,v 1.10 2009-11-14 17:56:39 tcunha Exp $ */
/* $Id: cmd-save-buffer.c,v 1.11 2010-07-02 02:52:13 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -48,7 +48,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
struct session *s;
struct paste_buffer *pb;
mode_t mask;
FILE *f;
FILE *f, *close_f;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
@@ -65,15 +65,25 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
}
}
mask = umask(S_IRWXG | S_IRWXO);
if (cmd_check_flag(data->chflags, 'a'))
f = fopen(data->arg, "ab");
else
f = fopen(data->arg, "wb");
umask(mask);
if (f == NULL) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
if (strcmp(data->arg, "-") == 0) {
if (ctx->cmdclient == NULL) {
ctx->error(ctx, "%s: can't write to stdout", data->arg);
return (-1);
}
f = ctx->cmdclient->stdout_file;
close_f = NULL;
} else {
mask = umask(S_IRWXG | S_IRWXO);
if (cmd_check_flag(data->chflags, 'a'))
f = fopen(data->arg, "ab");
else
f = fopen(data->arg, "wb");
umask(mask);
if (f == NULL) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
}
close_f = f;
}
if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
@@ -82,7 +92,8 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1);
}
fclose(f);
if (close_f != NULL)
fclose(close_f);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-select-layout.c,v 1.10 2009-12-04 22:14:47 tcunha Exp $ */
/* $Id: cmd-select-layout.c,v 1.12 2010-07-02 02:54:52 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -59,6 +59,9 @@ cmd_select_layout_init(struct cmd *self, int key)
case ('4' | KEYC_ESCAPE):
data->arg = xstrdup("main-vertical");
break;
case ('5' | KEYC_ESCAPE):
data->arg = xstrdup("tiled");
break;
}
}
@@ -76,13 +79,16 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
layout = wl->window->lastlayout;
if (layout == -1)
return (0);
} else if ((layout = layout_set_lookup(data->arg)) == -1) {
ctx->error(ctx, "unknown layout or ambiguous: %s", data->arg);
return (-1);
} else if ((layout = layout_set_lookup(data->arg)) != -1) {
layout = layout_set_select(wl->window, layout);
ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
} else {
if (layout_parse(wl->window, data->arg) == -1) {
ctx->error(ctx, "can't set layout: %s", data->arg);
return (-1);
}
ctx->info(ctx, "arranging in: %s", data->arg);
}
layout = layout_set_select(wl->window, layout);
ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-select-pane.c,v 1.12 2010-01-05 23:52:37 tcunha Exp $ */
/* $Id: cmd-select-pane.c,v 1.13 2010-03-15 22:03:38 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,19 +24,40 @@
* Select pane.
*/
void cmd_select_pane_init(struct cmd *, int);
int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_select_pane_entry = {
"select-pane", "selectp",
CMD_TARGET_PANE_USAGE,
0, "",
cmd_target_init,
"[-DLRU] " CMD_TARGET_PANE_USAGE,
0, "DLRU",
cmd_select_pane_init,
cmd_target_parse,
cmd_select_pane_exec,
cmd_target_free,
cmd_target_print
};
void
cmd_select_pane_init(struct cmd *self, int key)
{
struct cmd_target_data *data;
cmd_target_init(self, key);
data = self->data;
if (key == KEYC_UP)
cmd_set_flag(&data->chflags, 'U');
if (key == KEYC_DOWN)
cmd_set_flag(&data->chflags, 'D');
if (key == KEYC_LEFT)
cmd_set_flag(&data->chflags, 'L');
if (key == KEYC_RIGHT)
cmd_set_flag(&data->chflags, 'R');
if (key == 'o')
data->target = xstrdup(":.+");
}
int
cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
@@ -51,6 +72,20 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
ctx->error(ctx, "pane not visible: %s", data->target);
return (-1);
}
if (cmd_check_flag(data->chflags, 'L'))
wp = window_pane_find_left(wp);
else if (cmd_check_flag(data->chflags, 'R'))
wp = window_pane_find_right(wp);
else if (cmd_check_flag(data->chflags, 'U'))
wp = window_pane_find_up(wp);
else if (cmd_check_flag(data->chflags, 'D'))
wp = window_pane_find_down(wp);
if (wp == NULL) {
ctx->error(ctx, "pane not found");
return (-1);
}
window_set_active_pane(wl->window, wp);
server_status_window(wl->window);
server_redraw_window_borders(wl->window);

View File

@@ -1,91 +0,0 @@
/* $Id: cmd-select-prompt.c,v 1.13 2009-11-14 17:56:39 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Prompt for window index and select it.
*/
int cmd_select_prompt_exec(struct cmd *, struct cmd_ctx *);
int cmd_select_prompt_callback(void *, const char *);
const struct cmd_entry cmd_select_prompt_entry = {
"select-prompt", NULL,
CMD_TARGET_CLIENT_USAGE,
0, "",
cmd_target_init,
cmd_target_parse,
cmd_select_prompt_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_select_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct client *c;
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
if (c->prompt_string != NULL)
return (0);
status_prompt_set(c, "index ", cmd_select_prompt_callback, NULL, c, 0);
return (0);
}
int
cmd_select_prompt_callback(void *data, const char *s)
{
struct client *c = data;
const char *errstr;
char msg[128];
u_int idx;
if (s == NULL || *s == '\0')
return (0);
idx = strtonum(s, 0, UINT_MAX, &errstr);
if (errstr != NULL) {
xsnprintf(msg, sizeof msg, "Index %s: %s", errstr, s);
status_message_set(c, "%s", msg);
return (0);
}
if (winlink_find_by_index(&c->session->windows, idx) == NULL) {
xsnprintf(msg, sizeof msg,
"Window not found: %s:%d", c->session->name, idx);
status_message_set(c, "%s", msg);
return (0);
}
if (session_select(c->session, idx) == 0)
server_redraw_session(c->session);
recalculate_sizes();
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-send-keys.c,v 1.24 2009-12-04 22:14:47 tcunha Exp $ */
/* $Id: cmd-send-keys.c,v 1.25 2010-05-22 21:56:04 micahcowan Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -105,16 +105,17 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_send_keys_data *data = self->data;
struct window_pane *wp;
struct session *s;
u_int i;
if (data == NULL)
return (-1);
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL)
return (-1);
for (i = 0; i < data->nkeys; i++)
window_pane_key(wp, ctx->curclient, data->keys[i]);
window_pane_key(wp, s, data->keys[i]);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-send-prefix.c,v 1.28 2009-11-14 17:56:39 tcunha Exp $ */
/* $Id: cmd-send-prefix.c,v 1.29 2010-05-22 21:56:04 micahcowan Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -49,7 +49,7 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1);
keylist = options_get_data(&s->options, "prefix");
window_pane_key(wp, ctx->curclient, ARRAY_FIRST(keylist));
window_pane_key(wp, s, ARRAY_FIRST(keylist));
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-set-option.c,v 1.96 2010-02-26 13:31:39 tcunha Exp $ */
/* $Id: cmd-set-option.c,v 1.98 2010-07-02 02:45:52 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -87,6 +87,7 @@ const struct set_option_entry set_session_option_table[] = {
{ "default-path", SET_OPTION_STRING, 0, 0, NULL },
{ "default-shell", SET_OPTION_STRING, 0, 0, NULL },
{ "default-terminal", SET_OPTION_STRING, 0, 0, NULL },
{ "detach-on-destroy", SET_OPTION_FLAG, 0, 0, NULL },
{ "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL },
{ "display-panes-active-colour", SET_OPTION_COLOUR, 0, 0, NULL },
{ "display-panes-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL },
@@ -157,6 +158,9 @@ const struct set_option_entry set_window_option_table[] = {
{ "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL },
{ "synchronize-panes", SET_OPTION_FLAG, 0, 0, NULL },
{ "utf8", SET_OPTION_FLAG, 0, 0, NULL },
{ "window-status-alert-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "window-status-alert-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "window-status-alert-fg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "window-status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "window-status-current-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-split-window.c,v 1.34 2010-01-08 16:31:35 tcunha Exp $ */
/* $Id: cmd-split-window.c,v 1.35 2010-07-02 02:49:19 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -169,10 +169,13 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
cmd = data->cmd;
if (cmd == NULL)
cmd = options_get_string(&s->options, "default-command");
if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL)
cwd = options_get_string(&s->options, "default-path");
else
cwd = ctx->cmdclient->cwd;
cwd = options_get_string(&s->options, "default-path");
if (*cwd == '\0') {
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
cwd = ctx->cmdclient->cwd;
else
cwd = s->cwd;
}
type = LAYOUT_TOPBOTTOM;
if (data->flag_horizontal)

View File

@@ -1,60 +0,0 @@
/* $Id: cmd-up-pane.c,v 1.14 2010-01-05 23:52:37 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* 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"
/*
* Move up a pane.
*/
int cmd_up_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_up_pane_entry = {
"up-pane", "upp",
CMD_TARGET_WINDOW_USAGE,
0, "",
cmd_target_init,
cmd_target_parse,
cmd_up_pane_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_up_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct window *w;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
w = wl->window;
do {
w->active = TAILQ_PREV(w->active, window_panes, entry);
if (w->active == NULL)
w->active = TAILQ_LAST(&w->panes, window_panes);
} while (!window_pane_visible(w->active));
server_status_window(wl->window);
server_redraw_window_borders(wl->window);
return (0);
}

176
cmd.c
View File

@@ -1,4 +1,4 @@
/* $Id: cmd.c,v 1.137 2010-01-22 17:28:34 tcunha Exp $ */
/* $Id: cmd.c,v 1.142 2010-07-17 14:38:13 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,6 +31,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_bind_key_entry,
&cmd_break_pane_entry,
&cmd_capture_pane_entry,
&cmd_choose_buffer_entry,
&cmd_choose_client_entry,
&cmd_choose_session_entry,
&cmd_choose_window_entry,
@@ -44,7 +45,6 @@ const struct cmd_entry *cmd_table[] = {
&cmd_detach_client_entry,
&cmd_display_message_entry,
&cmd_display_panes_entry,
&cmd_down_pane_entry,
&cmd_find_window_entry,
&cmd_has_session_entry,
&cmd_if_shell_entry,
@@ -85,7 +85,6 @@ const struct cmd_entry *cmd_table[] = {
&cmd_save_buffer_entry,
&cmd_select_layout_entry,
&cmd_select_pane_entry,
&cmd_select_prompt_entry,
&cmd_select_window_entry,
&cmd_send_keys_entry,
&cmd_send_prefix_entry,
@@ -108,7 +107,6 @@ const struct cmd_entry *cmd_table[] = {
&cmd_switch_client_entry,
&cmd_unbind_key_entry,
&cmd_unlink_window_entry,
&cmd_up_pane_entry,
NULL
};
@@ -118,6 +116,9 @@ struct client *cmd_lookup_client(const char *);
struct session *cmd_lookup_session(const char *, int *);
struct winlink *cmd_lookup_window(struct session *, const char *, int *);
int cmd_lookup_index(struct session *, const char *, int *);
struct winlink *cmd_find_window_offset(const char *, struct session *, int *);
int cmd_find_index_offset(const char *, struct session *, int *);
struct window_pane *cmd_find_pane_offset(const char *, struct winlink *);
int
cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
@@ -540,7 +541,7 @@ cmd_lookup_session(const char *name, int *ambiguous)
/*
* Lookup a window or return -1 if not found or ambigious. First try as an
* index and if invalid, use fnmatch or leading prefix. Return NULL but fill in
* idx if the window index is a valid number but there is now window with that
* idx if the window index is a valid number but there is no window with that
* index.
*/
struct winlink *
@@ -707,10 +708,8 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp)
wl = s->curw;
else if (winptr[0] == '!' && winptr[1] == '\0')
wl = TAILQ_FIRST(&s->lastw);
else if (winptr[0] == '+' && winptr[1] == '\0')
wl = winlink_next(s->curw);
else if (winptr[0] == '-' && winptr[1] == '\0')
wl = winlink_previous(s->curw);
else if (winptr[0] == '+' || winptr[0] == '-')
wl = cmd_find_window_offset(winptr, s, &ambiguous);
else
wl = cmd_lookup_window(s, winptr, &ambiguous);
if (wl == NULL)
@@ -728,25 +727,28 @@ no_colon:
if (arg[0] == '!' && arg[1] == '\0') {
if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
goto not_found;
} else if (arg[0] == '+' && arg[1] == '\0') {
if ((wl = winlink_next(s->curw)) == NULL)
goto not_found;
} else if (arg[0] == '-' && arg[1] == '\0') {
if ((wl = winlink_previous(s->curw)) == NULL)
goto not_found;
} else if ((wl = cmd_lookup_window(s, arg, &ambiguous)) == NULL) {
if (ambiguous)
goto not_found;
if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL)
goto no_session;
wl = s->curw;
}
} else if (arg[0] == '+' || arg[0] == '-') {
if ((wl = cmd_find_window_offset(arg, s, &ambiguous)) == NULL)
goto lookup_session;
} else if ((wl = cmd_lookup_window(s, arg, &ambiguous)) == NULL)
goto lookup_session;
if (sp != NULL)
*sp = s;
return (wl);
lookup_session:
if (ambiguous)
goto not_found;
if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL)
goto no_session;
if (sp != NULL)
*sp = s;
return (s->curw);
no_session:
if (ambiguous)
ctx->error(ctx, "multiple sessions: %s", arg);
@@ -766,6 +768,26 @@ not_found:
return (NULL);
}
struct winlink *
cmd_find_window_offset(const char *winptr, struct session *s, int *ambiguous)
{
struct winlink *wl;
int offset = 1;
if (winptr[1] != '\0')
offset = strtonum(winptr + 1, 1, INT_MAX, NULL);
if (offset == 0)
wl = cmd_lookup_window(s, winptr, ambiguous);
else {
if (winptr[0] == '+')
wl = winlink_next_by_number(s->curw, s, offset);
else
wl = winlink_previous_by_number(s->curw, s, offset);
}
return (wl);
}
/*
* Find the target session and window index, whether or not it exists in the
* session. Return -2 on error or -1 if no window index is specified. This is
@@ -827,20 +849,11 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp)
if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
goto not_found;
idx = wl->idx;
} else if (winptr[0] == '+' && winptr[1] == '\0') {
if (s->curw->idx == INT_MAX)
goto not_found;
idx = s->curw->idx + 1;
} else if (winptr[0] == '-' && winptr[1] == '\0') {
if (s->curw->idx == 0)
goto not_found;
idx = s->curw->idx - 1;
} else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1) {
if (ambiguous)
goto not_found;
ctx->error(ctx, "invalid index: %s", arg);
idx = -2;
}
} else if (winptr[0] == '+' || winptr[0] == '-') {
if ((idx = cmd_find_index_offset(winptr, s, &ambiguous)) < 0)
goto invalid_index;
} else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1)
goto invalid_index;
if (sessptr != NULL)
xfree(sessptr);
@@ -855,27 +868,28 @@ no_colon:
if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
goto not_found;
idx = wl->idx;
} else if (arg[0] == '+' && arg[1] == '\0') {
if (s->curw->idx == INT_MAX)
goto not_found;
idx = s->curw->idx + 1;
} else if (arg[0] == '-' && arg[1] == '\0') {
if (s->curw->idx == 0)
goto not_found;
idx = s->curw->idx - 1;
} else if ((idx = cmd_lookup_index(s, arg, &ambiguous)) == -1) {
if (ambiguous)
goto not_found;
if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL)
goto no_session;
idx = -1;
}
} else if (arg[0] == '+' || arg[0] == '-') {
if ((idx = cmd_find_index_offset(arg, s, &ambiguous)) < 0)
goto lookup_session;
} else if ((idx = cmd_lookup_index(s, arg, &ambiguous)) == -1)
goto lookup_session;
if (sp != NULL)
*sp = s;
return (idx);
lookup_session:
if (ambiguous)
goto not_found;
if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL)
goto no_session;
if (sp != NULL)
*sp = s;
return (-1);
no_session:
if (ambiguous)
ctx->error(ctx, "multiple sessions: %s", arg);
@@ -885,6 +899,15 @@ no_session:
xfree(sessptr);
return (-2);
invalid_index:
if (ambiguous)
goto not_found;
ctx->error(ctx, "invalid index: %s", arg);
if (sessptr != NULL)
xfree(sessptr);
return (-2);
not_found:
if (ambiguous)
ctx->error(ctx, "multiple windows: %s", arg);
@@ -895,6 +918,32 @@ not_found:
return (-2);
}
int
cmd_find_index_offset(const char *winptr, struct session *s, int *ambiguous)
{
int idx, offset = 1;
if (winptr[1] != '\0')
offset = strtonum(winptr + 1, 1, INT_MAX, NULL);
if (offset == 0)
idx = cmd_lookup_index(s, winptr, ambiguous);
else {
if (winptr[0] == '+') {
if (s->curw->idx == INT_MAX)
idx = cmd_lookup_index(s, winptr, ambiguous);
else
idx = s->curw->idx + offset;
} else {
if (s->curw->idx == 0)
idx = cmd_lookup_index(s, winptr, ambiguous);
else
idx = s->curw->idx - offset;
}
}
return (idx);
}
/*
* Find the target session, window and pane number or report an error and
* return NULL. The pane number is separated from the session:window by a .,
@@ -941,6 +990,8 @@ cmd_find_pane(struct cmd_ctx *ctx,
paneptr = winptr + (period - arg) + 1;
if (*paneptr == '\0')
*wpp = wl->window->active;
else if (paneptr[0] == '+' || paneptr[0] == '-')
*wpp = cmd_find_pane_offset(paneptr, wl);
else {
idx = strtonum(paneptr, 0, INT_MAX, &errstr);
if (errstr != NULL)
@@ -955,14 +1006,14 @@ cmd_find_pane(struct cmd_ctx *ctx,
lookup_string:
/* Try pane string description. */
if ((lc = layout_find_string(s->curw->window, paneptr)) == NULL) {
if ((lc = layout_find_string(wl->window, paneptr)) == NULL) {
ctx->error(ctx, "can't find pane: %s", paneptr);
goto error;
}
*wpp = lc->wp;
xfree(winptr);
return (s->curw);
return (wl);
no_period:
/* Try as a pane number alone. */
@@ -993,6 +1044,25 @@ error:
return (NULL);
}
struct window_pane *
cmd_find_pane_offset(const char *paneptr, struct winlink *wl)
{
struct window *w = wl->window;
struct window_pane *wp = w->active;
u_int offset = 1;
if (paneptr[1] != '\0')
offset = strtonum(paneptr + 1, 1, INT_MAX, NULL);
if (offset > 0) {
if (paneptr[0] == '+')
wp = window_pane_next_by_number(w, wp, offset);
else
wp = window_pane_previous_by_number(w, wp, offset);
}
return (wp);
}
/* Replace the first %% or %idx in template by s. */
char *
cmd_template_replace(char *template, const char *s, int idx)

View File

@@ -1,4 +1,4 @@
/* $Id: compat.h,v 1.20 2009-11-08 22:51:34 tcunha Exp $ */
/* $Id: compat.h,v 1.25 2010-06-06 13:00:46 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -42,7 +42,7 @@ typedef uint64_t u_int64_t;
#else
#include "compat/tree.h"
#endif
#ifdef HAVE_BITSTRING_H
#include <bitstring.h>
#else
@@ -81,17 +81,36 @@ typedef uint64_t u_int64_t;
#ifndef HAVE_IMSG
#include "compat/imsg.h"
#else
#include <imsg.h>
#endif
#ifdef HAVE_BROKEN_CMSG_FIRSTHDR
/* Broken on OS X. */
/* CMSG_FIRSTHDR broken on OS X. */
#undef CMSG_FIRSTHDR
#define CMSG_FIRSTHDR(mhdr) \
((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \
(struct cmsghdr *)(mhdr)->msg_control : \
((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \
(struct cmsghdr *)(mhdr)->msg_control : \
(struct cmsghdr *)NULL)
#endif
/* CMSG_ALIGN, CMSG_SPACE, CMSG_LEN missing from Solaris 9. */
#ifndef CMSG_ALIGN
#ifdef __sun
#define CMSG_ALIGN _CMSG_DATA_ALIGN
#else
#define CMSG_ALIGN(len) (((len) + sizeof(long) - 1) & ~(sizeof(long) - 1))
#endif
#endif
#ifndef CMSG_SPACE
#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
#endif
#ifndef CMSG_LEN
#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
#endif
#ifndef INFTIM
#define INFTIM -1
#endif
@@ -135,7 +154,7 @@ typedef uint64_t u_int64_t;
#endif
#ifndef HAVE_BZERO
#define bzero(buf, len) memset((buf), 0, (len));
#define bzero(buf, len) memset(buf, 0, len);
#endif
#ifndef HAVE_STRCASESTR
@@ -175,13 +194,19 @@ pid_t forkpty(int *, char *, struct termios *, struct winsize *);
#ifndef HAVE_ASPRINTF
/* asprintf.c */
int asprintf(char **, const char *, ...);
int vasprintf(char **, const char *, va_list);
int asprintf(char **, const char *, ...);
int vasprintf(char **, const char *, va_list);
#endif
#ifndef HAVE_FGETLN
/* fgetln.c */
char *fgetln(FILE *, size_t *);
char *fgetln(FILE *, size_t *);
#endif
#ifndef HAVE_SETENV
/* setenv.c */
int setenv(const char *, const char *, int);
int unsetenv(const char *);
#endif
#ifndef HAVE_GETOPT

View File

@@ -1,5 +1,5 @@
/* $Id: imsg-buffer.c,v 1.4 2009-09-15 23:59:40 tcunha Exp $ */
/* $OpenBSD: imsg-buffer.c,v 1.2 2009/09/15 18:12:51 jacekm Exp $ */
/* $Id: imsg-buffer.c,v 1.5 2010-06-06 00:08:28 tcunha Exp $ */
/* $OpenBSD: imsg-buffer.c,v 1.3 2010/05/26 13:56:07 nicm Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -28,16 +28,16 @@
#include "tmux.h"
int buf_realloc(struct buf *, size_t);
void buf_enqueue(struct msgbuf *, struct buf *);
void buf_dequeue(struct msgbuf *, struct buf *);
int ibuf_realloc(struct ibuf *, size_t);
void ibuf_enqueue(struct msgbuf *, struct ibuf *);
void ibuf_dequeue(struct msgbuf *, struct ibuf *);
struct buf *
buf_open(size_t len)
struct ibuf *
ibuf_open(size_t len)
{
struct buf *buf;
struct ibuf *buf;
if ((buf = calloc(1, sizeof(struct buf))) == NULL)
if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
return (NULL);
if ((buf->buf = malloc(len)) == NULL) {
free(buf);
@@ -49,15 +49,15 @@ buf_open(size_t len)
return (buf);
}
struct buf *
buf_dynamic(size_t len, size_t max)
struct ibuf *
ibuf_dynamic(size_t len, size_t max)
{
struct buf *buf;
struct ibuf *buf;
if (max < len)
return (NULL);
if ((buf = buf_open(len)) == NULL)
if ((buf = ibuf_open(len)) == NULL)
return (NULL);
if (max > 0)
@@ -67,7 +67,7 @@ buf_dynamic(size_t len, size_t max)
}
int
buf_realloc(struct buf *buf, size_t len)
ibuf_realloc(struct ibuf *buf, size_t len)
{
u_char *b;
@@ -87,10 +87,10 @@ buf_realloc(struct buf *buf, size_t len)
}
int
buf_add(struct buf *buf, const void *data, size_t len)
ibuf_add(struct ibuf *buf, const void *data, size_t len)
{
if (buf->wpos + len > buf->size)
if (buf_realloc(buf, len) == -1)
if (ibuf_realloc(buf, len) == -1)
return (-1);
memcpy(buf->buf + buf->wpos, data, len);
@@ -99,12 +99,12 @@ buf_add(struct buf *buf, const void *data, size_t len)
}
void *
buf_reserve(struct buf *buf, size_t len)
ibuf_reserve(struct ibuf *buf, size_t len)
{
void *b;
if (buf->wpos + len > buf->size)
if (buf_realloc(buf, len) == -1)
if (ibuf_realloc(buf, len) == -1)
return (NULL);
b = buf->buf + buf->wpos;
@@ -113,7 +113,7 @@ buf_reserve(struct buf *buf, size_t len)
}
void *
buf_seek(struct buf *buf, size_t pos, size_t len)
ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
{
/* only allowed to seek in already written parts */
if (pos + len > buf->wpos)
@@ -123,28 +123,28 @@ buf_seek(struct buf *buf, size_t pos, size_t len)
}
size_t
buf_size(struct buf *buf)
ibuf_size(struct ibuf *buf)
{
return (buf->wpos);
}
size_t
buf_left(struct buf *buf)
ibuf_left(struct ibuf *buf)
{
return (buf->max - buf->wpos);
}
void
buf_close(struct msgbuf *msgbuf, struct buf *buf)
ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
{
buf_enqueue(msgbuf, buf);
ibuf_enqueue(msgbuf, buf);
}
int
buf_write(struct msgbuf *msgbuf)
ibuf_write(struct msgbuf *msgbuf)
{
struct iovec iov[IOV_MAX];
struct buf *buf;
struct ibuf *buf;
unsigned int i = 0;
ssize_t n;
@@ -176,7 +176,7 @@ buf_write(struct msgbuf *msgbuf)
}
void
buf_free(struct buf *buf)
ibuf_free(struct ibuf *buf)
{
free(buf->buf);
free(buf);
@@ -193,14 +193,14 @@ msgbuf_init(struct msgbuf *msgbuf)
void
msgbuf_drain(struct msgbuf *msgbuf, size_t n)
{
struct buf *buf, *next;
struct ibuf *buf, *next;
for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
buf = next) {
next = TAILQ_NEXT(buf, entry);
if (buf->rpos + n >= buf->wpos) {
n -= buf->wpos - buf->rpos;
buf_dequeue(msgbuf, buf);
ibuf_dequeue(msgbuf, buf);
} else {
buf->rpos += n;
n = 0;
@@ -211,17 +211,17 @@ msgbuf_drain(struct msgbuf *msgbuf, size_t n)
void
msgbuf_clear(struct msgbuf *msgbuf)
{
struct buf *buf;
struct ibuf *buf;
while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
buf_dequeue(msgbuf, buf);
ibuf_dequeue(msgbuf, buf);
}
int
msgbuf_write(struct msgbuf *msgbuf)
{
struct iovec iov[IOV_MAX];
struct buf *buf;
struct ibuf *buf;
unsigned int i = 0;
ssize_t n;
struct msghdr msg;
@@ -284,14 +284,14 @@ msgbuf_write(struct msgbuf *msgbuf)
}
void
buf_enqueue(struct msgbuf *msgbuf, struct buf *buf)
ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
{
TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
msgbuf->queued++;
}
void
buf_dequeue(struct msgbuf *msgbuf, struct buf *buf)
ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
{
TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
@@ -299,5 +299,5 @@ buf_dequeue(struct msgbuf *msgbuf, struct buf *buf)
close(buf->fd);
msgbuf->queued--;
buf_free(buf);
ibuf_free(buf);
}

View File

@@ -1,5 +1,5 @@
/* $Id: imsg.c,v 1.3 2009-08-20 12:54:08 nicm Exp $ */
/* $OpenBSD: imsg.c,v 1.1 2009/08/11 17:18:35 nicm Exp $ */
/* $Id: imsg.c,v 1.5 2010-06-06 00:08:28 tcunha Exp $ */
/* $OpenBSD: imsg.c,v 1.3 2010/05/26 13:56:07 nicm Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -79,7 +79,7 @@ imsg_read(struct imsgbuf *ibuf)
cmsg->cmsg_type == SCM_RIGHTS) {
fd = (*(int *)CMSG_DATA(cmsg));
if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) {
/* XXX: this return can leak */
close(fd);
return (-1);
}
ifd->fd = fd;
@@ -135,7 +135,7 @@ int
imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
pid_t pid, int fd, void *data, u_int16_t datalen)
{
struct buf *wbuf;
struct ibuf *wbuf;
if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
return (-1);
@@ -154,7 +154,7 @@ int
imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
pid_t pid, int fd, const struct iovec *iov, int iovcnt)
{
struct buf *wbuf;
struct ibuf *wbuf;
int i, datalen = 0;
for (i = 0; i < iovcnt; i++)
@@ -175,11 +175,11 @@ imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
}
/* ARGSUSED */
struct buf *
struct ibuf *
imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
pid_t pid, u_int16_t datalen)
{
struct buf *wbuf;
struct ibuf *wbuf;
struct imsg_hdr hdr;
datalen += IMSG_HEADER_SIZE;
@@ -193,7 +193,7 @@ imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
hdr.peerid = peerid;
if ((hdr.pid = pid) == 0)
hdr.pid = ibuf->pid;
if ((wbuf = buf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
return (NULL);
}
if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
@@ -203,18 +203,18 @@ imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
}
int
imsg_add(struct buf *msg, void *data, u_int16_t datalen)
imsg_add(struct ibuf *msg, void *data, u_int16_t datalen)
{
if (datalen)
if (buf_add(msg, data, datalen) == -1) {
buf_free(msg);
if (ibuf_add(msg, data, datalen) == -1) {
ibuf_free(msg);
return (-1);
}
return (datalen);
}
void
imsg_close(struct imsgbuf *ibuf, struct buf *msg)
imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
{
struct imsg_hdr *hdr;
@@ -226,7 +226,7 @@ imsg_close(struct imsgbuf *ibuf, struct buf *msg)
hdr->len = (u_int16_t)msg->wpos;
buf_close(&ibuf->w, msg);
ibuf_close(&ibuf->w, msg);
}
void

View File

@@ -1,5 +1,5 @@
/* $Id: imsg.h,v 1.4 2009-09-15 23:59:40 tcunha Exp $ */
/* $OpenBSD: imsg.h,v 1.2 2009/09/15 18:12:51 jacekm Exp $ */
/* $Id: imsg.h,v 1.5 2010-06-06 00:08:28 tcunha Exp $ */
/* $OpenBSD: imsg.h,v 1.4 2010/05/26 13:56:07 nicm Exp $ */
/*
* Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -21,12 +21,12 @@
#include "tmux.h"
#define READ_BUF_SIZE 65535
#define IBUF_READ_SIZE 65535
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
#define MAX_IMSGSIZE 16384
struct buf {
TAILQ_ENTRY(buf) entry;
struct ibuf {
TAILQ_ENTRY(ibuf) entry;
u_char *buf;
size_t size;
size_t max;
@@ -36,13 +36,13 @@ struct buf {
};
struct msgbuf {
TAILQ_HEAD(, buf) bufs;
TAILQ_HEAD(, ibuf) bufs;
u_int32_t queued;
int fd;
};
struct buf_read {
u_char buf[READ_BUF_SIZE];
struct ibuf_read {
u_char buf[IBUF_READ_SIZE];
u_char *rptr;
size_t wpos;
};
@@ -54,7 +54,7 @@ struct imsg_fd {
struct imsgbuf {
TAILQ_HEAD(, imsg_fd) fds;
struct buf_read r;
struct ibuf_read r;
struct msgbuf w;
int fd;
pid_t pid;
@@ -78,16 +78,16 @@ struct imsg {
/* buffer.c */
struct buf *buf_open(size_t);
struct buf *buf_dynamic(size_t, size_t);
int buf_add(struct buf *, const void *, size_t);
void *buf_reserve(struct buf *, size_t);
void *buf_seek(struct buf *, size_t, size_t);
size_t buf_size(struct buf *);
size_t buf_left(struct buf *);
void buf_close(struct msgbuf *, struct buf *);
int buf_write(struct msgbuf *);
void buf_free(struct buf *);
struct ibuf *ibuf_open(size_t);
struct ibuf *ibuf_dynamic(size_t, size_t);
int ibuf_add(struct ibuf *, const void *, size_t);
void *ibuf_reserve(struct ibuf *, size_t);
void *ibuf_seek(struct ibuf *, size_t, size_t);
size_t ibuf_size(struct ibuf *);
size_t ibuf_left(struct ibuf *);
void ibuf_close(struct msgbuf *, struct ibuf *);
int ibuf_write(struct msgbuf *);
void ibuf_free(struct ibuf *);
void msgbuf_init(struct msgbuf *);
void msgbuf_clear(struct msgbuf *);
int msgbuf_write(struct msgbuf *);
@@ -101,10 +101,10 @@ int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
int, void *, u_int16_t);
int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
int, const struct iovec *, int);
struct buf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
struct ibuf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
u_int16_t);
int imsg_add(struct buf *, void *, u_int16_t);
void imsg_close(struct imsgbuf *, struct buf *);
int imsg_add(struct ibuf *, void *, u_int16_t);
void imsg_close(struct imsgbuf *, struct ibuf *);
void imsg_free(struct imsg *);
int imsg_flush(struct imsgbuf *);
void imsg_clear(struct imsgbuf *);

49
compat/setenv.c Normal file
View File

@@ -0,0 +1,49 @@
/* $Id: setenv.c,v 1.2 2010-06-05 18:20:48 nicm Exp $ */
/*
* Copyright (c) 2010 Dagobert Michelsen
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
*
* 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 <stdlib.h>
#include <string.h>
#include "tmux.h"
int
setenv(const char *name, const char *value, unused int overwrite)
{
char *newval;
xasprintf(&newval, "%s=%s", name, value);
return (putenv(newval));
}
int
unsetenv(const char *name)
{
char **envptr;
int namelen;
namelen = strlen(name);
for (envptr = environ; *envptr != NULL; envptr++) {
if (strncmp(name, *envptr, namelen) == 0 &&
((*envptr)[namelen] == '=' || (*envptr)[namelen] == '\0'))
break;
}
for (; *envptr != NULL; envptr++)
*envptr = *(envptr + 1);
return (0);
}

35
configure vendored
View File

@@ -1,5 +1,5 @@
#!/bin/sh
# $Id: configure,v 1.47 2009-12-11 20:08:18 nicm Exp $
# $Id: configure,v 1.53 2010-06-06 13:00:47 tcunha Exp $
#
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
#
@@ -67,9 +67,11 @@ case $TMUX_PLATFORM in
#define HAVE_FGETLN
#define HAVE_FORKPTY
#define HAVE_GETOPT
#define HAVE_IMSG
#define HAVE_PATHS_H
#define HAVE_PROGNAME
#define HAVE_QUEUE_H
#define HAVE_SETENV
#define HAVE_SETPROCTITLE
#define HAVE_STRCASESTR
#define HAVE_STRLCAT
@@ -83,9 +85,7 @@ case $TMUX_PLATFORM in
EOF
cat <<EOF >>$CONFIG_MK
LIBS+= -lcurses -lutil -levent
SRCS+= osdep-openbsd.c \
compat/imsg-buffer.c \
compat/imsg.c
SRCS+= osdep-openbsd.c
EOF
;;
# ------------------------------------------------------------------------------
@@ -98,13 +98,14 @@ EOF
#define HAVE_PATHS_H
#define HAVE_PROGNAME
#define HAVE_PTY_H
#define HAVE_SETENV
#define HAVE_STRCASESTR
#define HAVE_STRSEP
#define HAVE_U_INT
EOF
cat <<EOF >>$CONFIG_MK
CFLAGS+= -std=c99 -D_GNU_SOURCE -D_POSIX_SOURCE
LIBS+= -lncurses -lcrypt -lutil -levent
LIBS+= -lncurses -lcrypt -lutil -levent -lrt
SRCS+= osdep-linux.c \
compat/fgetln.c \
compat/strlcat.c \
@@ -122,6 +123,7 @@ EOF
cat <<EOF >>$CONFIG_H
#define HAVE_BZERO
#define HAVE_DAEMON
#define HAVE_SETENV
EOF
cat <<EOF >>$CONFIG_MK
LIBS+= -lcurses -levent
@@ -158,6 +160,7 @@ SRCS+= osdep-sunos.c \
compat/fgetln.c \
compat/forkpty-sunos.c \
compat/getopt.c \
compat/setenv.c \
compat/strcasestr.c \
compat/strsep.c \
compat/strtonum.c \
@@ -181,6 +184,7 @@ EOF
#define HAVE_GETOPT
#define HAVE_PATHS_H
#define HAVE_PROGNAME
#define HAVE_SETENV
#define HAVE_STRCASESTR
#define HAVE_STRLCAT
#define HAVE_STRLCPY
@@ -204,6 +208,7 @@ EOF
FreeBSD|DragonFly)
cat <<EOF >>$CONFIG_H
#define HAVE_ASPRINTF
#define HAVE_BROKEN_KQUEUE
#define HAVE_BZERO
#define HAVE_DAEMON
#define HAVE_FGETLN
@@ -212,6 +217,7 @@ EOF
#define HAVE_LIBUTIL_H
#define HAVE_PATHS_H
#define HAVE_PROGNAME
#define HAVE_SETENV
#define HAVE_SETPROCTITLE
#define HAVE_STRCASESTR
#define HAVE_STRLCAT
@@ -233,7 +239,6 @@ EOF
NetBSD)
cat <<EOF >>$CONFIG_H
#define HAVE_ASPRINTF
#define HAVE_BROKEN_CURSES_H
#define HAVE_BZERO
#define HAVE_DAEMON
#define HAVE_FGETLN
@@ -242,6 +247,7 @@ EOF
#define HAVE_PATHS_H
#define HAVE_PROGNAME
#define HAVE_SETPROCTITLE
#define HAVE_SETENV
#define HAVE_STRCASESTR
#define HAVE_STRLCAT
#define HAVE_STRLCPY
@@ -249,10 +255,23 @@ EOF
#define HAVE_UTIL_H
#define HAVE_U_INT
EOF
cat <<EOF >>$CONFIG_MK
# NetBSD-6 has its own terminfo implementation
if test -f /lib/libterminfo.so; then
cat <<EOF >>$CONFIG_MK
LIBS+= -lterminfo
EOF
else
cat <<EOF >>$CONFIG_MK
CPPFLAGS+= -I/usr/pkg/include
LDFLAGS+= -L/usr/pkg/lib
LIBS+= -lncurses -lcrypt -lutil -levent
LIBS+= -lncurses
EOF
cat <<EOF >>$CONFIG_H
#define HAVE_BROKEN_CURSES_H
EOF
fi
cat <<EOF >>$CONFIG_MK
LIBS+= -lcrypt -lutil -levent
SRCS+= osdep-netbsd.c \
compat/strtonum.c \
compat/vis.c \

View File

@@ -1,4 +1,4 @@
/* $Id: environ.c,v 1.3 2009-08-09 17:57:39 tcunha Exp $ */
/* $Id: environ.c,v 1.4 2010-04-06 21:59:19 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -35,12 +35,14 @@ environ_cmp(struct environ_entry *envent1, struct environ_entry *envent2)
return (strcmp(envent1->name, envent2->name));
}
/* Initialise the environment. */
void
environ_init(struct environ *env)
{
RB_INIT(env);
}
/* Free an environment. */
void
environ_free(struct environ *env)
{
@@ -56,6 +58,7 @@ environ_free(struct environ *env)
}
}
/* Copy one environment into another. */
void
environ_copy(struct environ *srcenv, struct environ *dstenv)
{
@@ -65,6 +68,7 @@ environ_copy(struct environ *srcenv, struct environ *dstenv)
environ_set(dstenv, envent->name, envent->value);
}
/* Find an environment variable. */
struct environ_entry *
environ_find(struct environ *env, const char *name)
{
@@ -74,6 +78,7 @@ environ_find(struct environ *env, const char *name)
return (RB_FIND(environ, env, &envent));
}
/* Set an environment variable. */
void
environ_set(struct environ *env, const char *name, const char *value)
{
@@ -97,10 +102,11 @@ environ_set(struct environ *env, const char *name, const char *value)
}
}
/* Set an environment variable from a NAME=VALUE string. */
void
environ_put(struct environ *env, const char *var)
{
char *name, *value;
char *name, *value;
value = strchr(var, '=');
if (value == NULL)
@@ -114,6 +120,7 @@ environ_put(struct environ *env, const char *var)
xfree(name);
}
/* Unset an environment variable. */
void
environ_unset(struct environ *env, const char *name)
{
@@ -128,6 +135,10 @@ environ_unset(struct environ *env, const char *name)
xfree(envent);
}
/*
* Copy a space-separated list of variables from a destination into a source
* environment.
*/
void
environ_update(const char *vars, struct environ *srcenv, struct environ *dstenv)
{
@@ -143,3 +154,28 @@ environ_update(const char *vars, struct environ *srcenv, struct environ *dstenv)
}
xfree(copyvars);
}
/* Push environment into the real environment - use after fork(). */
void
environ_push(struct environ *env)
{
ARRAY_DECL(, char *) varlist;
struct environ_entry *envent;
char **varp, *var;
u_int i;
ARRAY_INIT(&varlist);
for (varp = environ; *varp != NULL; varp++) {
var = xstrdup(*varp);
var[strcspn(var, "=")] = '\0';
ARRAY_ADD(&varlist, var);
}
for (i = 0; i < ARRAY_LENGTH(&varlist); i++)
unsetenv(ARRAY_ITEM(&varlist, i));
ARRAY_FREE(&varlist);
RB_FOREACH(envent, environ, env) {
if (envent->value != NULL)
setenv(envent->name, envent->value, 1);
}
}

View File

@@ -1,7 +1,7 @@
" Vim syntax file
" Language: tmux(1) configuration file
" Maintainer: Tiago Cunha <me@tiagocunha.org>
" Last Change: $Date: 2010-02-26 13:33:22 $
" Last Change: $Date: 2010-07-02 02:46:39 $
" License: This file is placed in the public domain.
if version < 600
@@ -29,7 +29,7 @@ syn keyword tmuxCmds new[-session] start[-server] kill-server setw
syn keyword tmuxCmds set-window-option show[-options] showw show-window-options
syn keyword tmuxCmds command-prompt setb set-buffer showb show-buffer lsb
syn keyword tmuxCmds list-buffers deleteb delete-buffer lscm list-commands
syn keyword tmuxCmds movew move-window select-prompt respawnw respawn-window
syn keyword tmuxCmds movew move-window respawnw respawn-window
syn keyword tmuxCmds source[-file] info server-info clock-mode lock[-server]
syn keyword tmuxCmds saveb save-buffer downp down-pane killp
syn keyword tmuxCmds kill-pane resizep resize-pane selectp select-pane swapp
@@ -42,7 +42,7 @@ syn keyword tmuxCmds display[-message] setenv set-environment showenv
syn keyword tmuxCmds show-environment choose-client displayp display-panes
syn keyword tmuxCmds run[-shell] lockc lock-client locks lock-session lsp
syn keyword tmuxCmds list-panes pipep pipe-pane showmsgs show-messages capturep
syn keyword tmuxCmds capture-pane joinp join-pane
syn keyword tmuxCmds capture-pane joinp join-pane choose-buffer
syn keyword tmuxOptsSet prefix status status-fg status-bg bell-action
syn keyword tmuxOptsSet default-command history-limit status-left status-right
@@ -61,6 +61,7 @@ syn keyword tmuxOptsSet mouse-select-pane message-limit quiet escape-time
syn keyword tmuxOptsSet pane-active-border-bg pane-active-border-fg
syn keyword tmuxOptsSet pane-border-bg pane-border-fg
syn keyword tmuxOptsSet display-panes-active-colour alternate-screen
syn keyword tmuxOptsSet detach-on-destroy
syn keyword tmuxOptsSetw monitor-activity aggressive-resize force-width
syn keyword tmuxOptsSetw force-height remain-on-exit uft8 mode-fg mode-bg

43
grid.c
View File

@@ -1,4 +1,4 @@
/* $Id: grid.c,v 1.36 2009-12-04 22:14:47 tcunha Exp $ */
/* $Id: grid.c,v 1.37 2010-04-05 05:11:43 micahcowan Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -46,18 +46,9 @@ const struct grid_cell grid_default_cell = { 0, 0, 8, 8, ' ' };
gc, sizeof gd->linedata[py].utf8data[px]); \
} while (0)
int grid_check_x(struct grid *, u_int);
int grid_check_y(struct grid *, u_int);
#ifdef DEBUG
int
grid_check_x(struct grid *gd, u_int px)
{
if ((px) >= (gd)->sx)
log_fatalx("x out of range: %u", px);
return (0);
}
int
grid_check_y(struct grid *gd, u_int py)
{
@@ -66,16 +57,6 @@ grid_check_y(struct grid *gd, u_int py)
return (0);
}
#else
int
grid_check_x(struct grid *gd, u_int px)
{
if ((px) >= (gd)->sx) {
log_debug("x out of range: %u", px);
return (-1);
}
return (0);
}
int
grid_check_y(struct grid *gd, u_int py)
{
@@ -270,8 +251,6 @@ grid_expand_line_utf8(struct grid *gd, u_int py, u_int sx)
const struct grid_cell *
grid_peek_cell(struct grid *gd, u_int px, u_int py)
{
if (grid_check_x(gd, px) != 0)
return (&grid_default_cell);
if (grid_check_y(gd, py) != 0)
return (&grid_default_cell);
@@ -284,8 +263,6 @@ grid_peek_cell(struct grid *gd, u_int px, u_int py)
struct grid_cell *
grid_get_cell(struct grid *gd, u_int px, u_int py)
{
if (grid_check_x(gd, px) != 0)
return (NULL);
if (grid_check_y(gd, py) != 0)
return (NULL);
@@ -298,8 +275,6 @@ void
grid_set_cell(
struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
{
if (grid_check_x(gd, px) != 0)
return;
if (grid_check_y(gd, py) != 0)
return;
@@ -311,8 +286,6 @@ grid_set_cell(
const struct grid_utf8 *
grid_peek_utf8(struct grid *gd, u_int px, u_int py)
{
if (grid_check_x(gd, px) != 0)
return (NULL);
if (grid_check_y(gd, py) != 0)
return (NULL);
@@ -325,8 +298,6 @@ grid_peek_utf8(struct grid *gd, u_int px, u_int py)
struct grid_utf8 *
grid_get_utf8(struct grid *gd, u_int px, u_int py)
{
if (grid_check_x(gd, px) != 0)
return (NULL);
if (grid_check_y(gd, py) != 0)
return (NULL);
@@ -339,8 +310,6 @@ void
grid_set_utf8(
struct grid *gd, u_int px, u_int py, const struct grid_utf8 *gc)
{
if (grid_check_x(gd, px) != 0)
return;
if (grid_check_y(gd, py) != 0)
return;
@@ -364,10 +333,6 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny)
return;
}
if (grid_check_x(gd, px) != 0)
return;
if (grid_check_x(gd, px + nx - 1) != 0)
return;
if (grid_check_y(gd, py) != 0)
return;
if (grid_check_y(gd, py + ny - 1) != 0)
@@ -465,12 +430,6 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx)
if (nx == 0 || px == dx)
return;
if (grid_check_x(gd, px) != 0)
return;
if (grid_check_x(gd, px + nx - 1) != 0)
return;
if (grid_check_x(gd, dx + nx - 1) != 0)
return;
if (grid_check_y(gd, py) != 0)
return;
gl = &gd->linedata[py];

2397
input.c

File diff suppressed because it is too large Load Diff

7
job.c
View File

@@ -1,4 +1,4 @@
/* $Id: job.c,v 1.15 2010-02-26 13:35:04 tcunha Exp $ */
/* $Id: job.c,v 1.17 2010-05-14 14:30:01 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -148,8 +148,9 @@ job_run(struct job *job)
case -1:
return (-1);
case 0: /* child */
server_signal_clear();
/* XXX environ? */
clear_signals();
environ_push(&global_environ);
if (dup2(out[1], STDOUT_FILENO) == -1)
fatal("dup2 failed");

View File

@@ -1,4 +1,4 @@
/* $Id: key-bindings.c,v 1.88 2010-02-08 18:27:34 tcunha Exp $ */
/* $Id: key-bindings.c,v 1.94 2010-07-02 02:43:01 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -122,10 +122,11 @@ key_bindings_init(void)
{ '8', 0, &cmd_select_window_entry },
{ '9', 0, &cmd_select_window_entry },
{ ':', 0, &cmd_command_prompt_entry },
{ '=', 0, &cmd_choose_buffer_entry },
{ '?', 0, &cmd_list_keys_entry },
{ 'D', 0, &cmd_choose_client_entry },
{ '[', 0, &cmd_copy_mode_entry },
{ '\'', 0, &cmd_select_prompt_entry },
{ '\'', 0, &cmd_command_prompt_entry },
{ '\002', /* C-b */ 0, &cmd_send_prefix_entry },
{ '\017', /* C-o */ 0, &cmd_rotate_window_entry },
{ '\032', /* C-z */ 0, &cmd_suspend_client_entry },
@@ -136,7 +137,7 @@ key_bindings_init(void)
{ 'i', 0, &cmd_display_message_entry },
{ 'l', 0, &cmd_last_window_entry },
{ 'n', 0, &cmd_next_window_entry },
{ 'o', 0, &cmd_down_pane_entry },
{ 'o', 0, &cmd_select_pane_entry },
{ 'p', 0, &cmd_previous_window_entry },
{ 'q', 0, &cmd_display_panes_entry },
{ 'r', 0, &cmd_refresh_client_entry },
@@ -151,12 +152,15 @@ key_bindings_init(void)
{ '2' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ '3' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ '4' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ '5' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ KEYC_PPAGE, 0, &cmd_copy_mode_entry },
{ 'n' | KEYC_ESCAPE, 0, &cmd_next_window_entry },
{ 'o' | KEYC_ESCAPE, 0, &cmd_rotate_window_entry },
{ 'p' | KEYC_ESCAPE, 0, &cmd_previous_window_entry },
{ KEYC_UP, 0, &cmd_up_pane_entry },
{ KEYC_DOWN, 0, &cmd_down_pane_entry },
{ KEYC_UP, 1, &cmd_select_pane_entry },
{ KEYC_DOWN, 1, &cmd_select_pane_entry },
{ KEYC_LEFT, 1, &cmd_select_pane_entry },
{ KEYC_RIGHT, 1, &cmd_select_pane_entry },
{ KEYC_UP | KEYC_ESCAPE, 1, &cmd_resize_pane_entry },
{ KEYC_DOWN | KEYC_ESCAPE, 1, &cmd_resize_pane_entry },
{ KEYC_LEFT | KEYC_ESCAPE, 1, &cmd_resize_pane_entry },
@@ -174,14 +178,15 @@ key_bindings_init(void)
for (i = 0; i < nitems(table); i++) {
cmdlist = xmalloc(sizeof *cmdlist);
TAILQ_INIT(cmdlist);
TAILQ_INIT(&cmdlist->list);
cmdlist->references = 1;
cmd = xmalloc(sizeof *cmd);
cmd->entry = table[i].entry;
cmd->data = NULL;
if (cmd->entry->init != NULL)
cmd->entry->init(cmd, table[i].key);
TAILQ_INSERT_HEAD(cmdlist, cmd, qentry);
TAILQ_INSERT_HEAD(&cmdlist->list, cmd, qentry);
key_bindings_add(
table[i].key | KEYC_PREFIX, table[i].can_repeat, cmdlist);
@@ -209,12 +214,14 @@ key_bindings_print(struct cmd_ctx *ctx, const char *fmt, ...)
struct winlink *wl = ctx->curclient->session->curw;
va_list ap;
if (wl->window->active->mode != &window_more_mode)
if (wl->window->active->mode != &window_copy_mode) {
window_pane_reset_mode(wl->window->active);
window_pane_set_mode(wl->window->active, &window_more_mode);
window_pane_set_mode(wl->window->active, &window_copy_mode);
window_copy_init_for_output(wl->window->active);
}
va_start(ap, fmt);
window_more_vadd(wl->window->active, fmt, ap);
window_copy_vadd(wl->window->active, fmt, ap);
va_end(ap);
}
@@ -253,7 +260,7 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c)
ctx.cmdclient = NULL;
readonly = 1;
TAILQ_FOREACH(cmd, bd->cmdlist, qentry) {
TAILQ_FOREACH(cmd, &bd->cmdlist->list, qentry) {
if (!(cmd->entry->flags & CMD_READONLY))
readonly = 0;
}

View File

@@ -1,4 +1,4 @@
/* $Id: key-string.c,v 1.29 2010-01-17 19:01:27 tcunha Exp $ */
/* $Id: key-string.c,v 1.34 2010-06-05 20:29:11 micahcowan Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -23,10 +23,11 @@
#include "tmux.h"
int key_string_search_table(const char *);
int key_string_get_modifiers(const char **);
struct {
const char *string;
int key;
const char *string;
int key;
} key_string_table[] = {
/* Function keys. */
{ "F1", KEYC_F1 },
@@ -100,146 +101,131 @@ key_string_search_table(const char *string)
return (KEYC_NONE);
}
/* Lookup a string and convert to a key value, handling C-/M-/S- prefix. */
/* Find modifiers. */
int
key_string_get_modifiers(const char **string)
{
int modifiers;
modifiers = 0;
while (((*string)[0] != '\0') && (*string)[1] == '-') {
switch ((*string)[0]) {
case 'C':
case 'c':
modifiers |= KEYC_CTRL;
break;
case 'M':
case 'm':
modifiers |= KEYC_ESCAPE;
break;
case 'S':
case 's':
modifiers |= KEYC_SHIFT;
break;
}
*string += 2;
}
return (modifiers);
}
/* Lookup a string and convert to a key value. */
int
key_string_lookup_string(const char *string)
{
int key;
const char *ptr;
int key, modifiers;
/* Check for modifiers. */
modifiers = 0;
if (string[0] == '^' && string[1] != '\0') {
modifiers |= KEYC_CTRL;
string++;
}
modifiers |= key_string_get_modifiers(&string);
if (string[0] == '\0')
return (KEYC_NONE);
if (string[1] == '\0')
return ((u_char) string[0]);
ptr = NULL;
if ((string[0] == 'C' || string[0] == 'c') && string[1] == '-')
ptr = string + 2;
else if (string[0] == '^')
ptr = string + 1;
if (ptr != NULL) {
if (ptr[0] == '\0')
/* Is this a standard ASCII key? */
if (string[1] == '\0') {
key = (u_char) string[0];
if (key < 32 || key > 126)
return (KEYC_NONE);
/*
* Lookup as a named key. If a function key (>= KEYC_BASE),
* return it with the ctrl modifier, otherwise fallthrough with
* the key value from the table (eg for C-Space). If not a
* named key, check for single character keys and try that.
*/
key = key_string_search_table(ptr);
if (key != KEYC_NONE) {
if (key >= KEYC_BASE)
return (key | KEYC_CTRL);
} else {
if (ptr[1] != '\0')
return (KEYC_NONE);
key = (u_char) ptr[0];
}
} else {
/* Otherwise look the key up in the table. */
key = key_string_search_table(string);
if (key == KEYC_NONE)
return (KEYC_NONE);
}
/*
* Figure out if the single character in key is a valid ctrl
* key.
*/
if (key == 32)
return (0);
if (key == 63)
return (KEYC_BSPACE);
if (key >= 64 && key <= 95)
return (key - 64);
/* Convert the standard control keys. */
if (key < KEYC_BASE && (modifiers & KEYC_CTRL)) {
if (key >= 97 && key <= 122)
return (key - 96);
return (KEYC_NONE);
}
if ((string[0] == 'M' || string[0] == 'm') && string[1] == '-') {
ptr = string + 2;
if (ptr[0] == '\0')
key -= 96;
else if (key >= 64 && key <= 95)
key -= 64;
else if (key == 32)
key = 0;
else if (key == 63)
key = KEYC_BSPACE;
else
return (KEYC_NONE);
key = key_string_lookup_string(ptr);
if (key != KEYC_NONE) {
if (key >= KEYC_BASE)
return (key | KEYC_ESCAPE);
} else {
if (ptr[1] == '\0')
return (KEYC_NONE);
key = (u_char) ptr[0];
}
if (key >= 32 && key <= 127)
return (key | KEYC_ESCAPE);
return (KEYC_NONE);
modifiers &= ~KEYC_CTRL;
}
if ((string[0] == 'S' || string[0] == 's') && string[1] == '-') {
ptr = string + 2;
if (ptr[0] == '\0')
return (KEYC_NONE);
key = key_string_lookup_string(ptr);
if (key != KEYC_NONE) {
if (key >= KEYC_BASE)
return (key | KEYC_SHIFT);
} else {
if (ptr[1] == '\0')
return (KEYC_NONE);
key = (u_char) ptr[0];
}
if (key >= 32 && key <= 127)
return (key | KEYC_SHIFT);
return (KEYC_NONE);
}
return (key_string_search_table(string));
return (key | modifiers);
}
/* Convert a key code into string format, with prefix if necessary. */
const char *
key_string_lookup_key(int key)
{
static char tmp[24], tmp2[24];
const char *s;
u_int i;
static char out[24];
char tmp[8];
u_int i;
if (key == 127)
return (NULL);
*out = '\0';
if (key & KEYC_ESCAPE) {
if ((s = key_string_lookup_key(key & ~KEYC_ESCAPE)) == NULL)
return (NULL);
xsnprintf(tmp2, sizeof tmp2, "M-%s", s);
return (tmp2);
}
if (key & KEYC_CTRL) {
if ((s = key_string_lookup_key(key & ~KEYC_CTRL)) == NULL)
return (NULL);
xsnprintf(tmp2, sizeof tmp2, "C-%s", s);
return (tmp2);
}
if (key & KEYC_SHIFT) {
if ((s = key_string_lookup_key(key & ~KEYC_SHIFT)) == NULL)
return (NULL);
xsnprintf(tmp2, sizeof tmp2, "S-%s", s);
return (tmp2);
}
/*
* Special case: display C-@ as C-Space. Could do this below in
* the (key >= 0 && key <= 32), but this way we let it be found
* in key_string_table, for the unlikely chance that we might
* change its name.
*/
if ((key & KEYC_MASK_KEY) == 0)
key = ' ' | KEYC_CTRL | (key & KEYC_MASK_MOD);
/* Fill in the modifiers. */
if (key & KEYC_CTRL)
strlcat(out, "C-", sizeof out);
if (key & KEYC_ESCAPE)
strlcat(out, "M-", sizeof out);
if (key & KEYC_SHIFT)
strlcat(out, "S-", sizeof out);
key &= KEYC_MASK_KEY;
/* Try the key against the string table. */
for (i = 0; i < nitems(key_string_table); i++) {
if (key == key_string_table[i].key)
return (key_string_table[i].string);
break;
}
if (i != nitems(key_string_table)) {
strlcat(out, key_string_table[i].string, sizeof out);
return (out);
}
if (key >= 32 && key <= 255) {
tmp[0] = (char) key;
tmp[1] = '\0';
return (tmp);
}
/* Invalid keys are errors. */
if (key >= 127)
return (NULL);
/* Check for standard or control key. */
if (key >= 0 && key <= 32) {
if (key == 0 || key > 26)
xsnprintf(tmp, sizeof tmp, "C-%c", 64 + key);
else
xsnprintf(tmp, sizeof tmp, "C-%c", 96 + key);
return (tmp);
} else if (key >= 32 && key <= 126) {
tmp[0] = key;
tmp[1] = '\0';
}
return (NULL);
strlcat(out, tmp, sizeof out);
return (out);
}

264
layout-custom.c Normal file
View File

@@ -0,0 +1,264 @@
/* $Id: layout-custom.c,v 1.1 2010-07-02 02:54:52 tcunha Exp $ */
/*
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <string.h>
#include "tmux.h"
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 *);
/* Calculate layout checksum. */
u_short
layout_checksum(const char *layout)
{
u_short csum;
csum = 0;
for (; *layout != '\0'; layout++) {
csum = (csum >> 1) + ((csum & 1) << 15);
csum += *layout;
}
return (csum);
}
/* Dump layout as a string. */
char *
layout_dump(struct window *w)
{
char layout[BUFSIZ], *out;
*layout = '\0';
if (layout_append(w->layout_root, layout, sizeof layout) != 0)
return (NULL);
xasprintf(&out, "%4x,%s", layout_checksum(layout), layout);
return (out);
}
/* Append information for a single cell. */
int
layout_append(struct layout_cell *lc, char *buf, size_t len)
{
struct layout_cell *lcchild;
char tmp[64];
size_t tmplen;
const char *brackets = "][";
if (len == 0)
return (-1);
tmplen = xsnprintf(tmp, sizeof tmp,
"%ux%u,%u,%u", lc->sx, lc->sy, lc->xoff, lc->yoff);
if (tmplen > (sizeof tmp) - 1)
return (-1);
if (strlcat(buf, tmp, len) >= len)
return (-1);
switch (lc->type) {
case LAYOUT_LEFTRIGHT:
brackets = "}{";
/* FALLTHROUGH */
case LAYOUT_TOPBOTTOM:
if (strlcat(buf, &brackets[1], len) >= len)
return (-1);
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (layout_append(lcchild, buf, len) != 0)
return (-1);
if (strlcat(buf, ",", len) >= len)
return (-1);
}
buf[strlen(buf) - 1] = brackets[0];
break;
case LAYOUT_WINDOWPANE:
break;
}
return (0);
}
/* Parse a layout string and arrange window as layout. */
int
layout_parse(struct window *w, const char *layout)
{
struct layout_cell *lc, *lcchild;
struct window_pane *wp;
u_int npanes, ncells, sx, sy;
u_short csum;
/* Check validity. */
if (sscanf(layout, "%hx,", &csum) != 1)
return (-1);
layout += 5;
if (csum != layout_checksum(layout))
return (-1);
/* Build the layout. */
lc = layout_construct(NULL, &layout);
if (lc == NULL)
return (-1);
if (*layout != '\0')
goto fail;
/* Check this window will fit into the layout. */
for (;;) {
npanes = window_count_panes(w);
ncells = layout_count_cells(lc);
if (npanes > ncells)
goto fail;
if (npanes == ncells)
break;
/* Fewer panes than cells - close the bottom right. */
lcchild = layout_find_bottomright(lc);
layout_destroy_cell(lcchild, &lc);
}
/* Save the old window size and resize to the layout size. */
sx = w->sx; sy = w->sy;
window_resize(w, lc->sx, lc->sy);
/* Destroy the old layout and swap to the new. */
layout_free_cell(w->layout_root);
w->layout_root = lc;
/* Assign the panes into the cells. */
wp = TAILQ_FIRST(&w->panes);
layout_assign(&wp, lc);
/* Update pane offsets and sizes. */
layout_fix_offsets(lc);
layout_fix_panes(w, lc->sx, lc->sy);
/* Then resize the layout back to the original window size. */
layout_resize(w, sx, sy);
window_resize(w, sx, sy);
layout_print_cell(lc, __func__, 0);
return (0);
fail:
layout_free_cell(lc);
return (-1);
}
/* Assign panes into cells. */
void
layout_assign(struct window_pane **wp, struct layout_cell *lc)
{
struct layout_cell *lcchild;
switch (lc->type) {
case LAYOUT_WINDOWPANE:
layout_make_leaf(lc, *wp);
*wp = TAILQ_NEXT(*wp, entry);
return;
case LAYOUT_LEFTRIGHT:
case LAYOUT_TOPBOTTOM:
TAILQ_FOREACH(lcchild, &lc->cells, entry)
layout_assign(wp, lcchild);
return;
}
}
/* Construct a cell from all or part of a layout tree. */
struct layout_cell *
layout_construct(struct layout_cell *lcparent, const char **layout)
{
struct layout_cell *lc, *lcchild;
u_int sx, sy, xoff, yoff;
if (!isdigit((u_char) **layout))
return (NULL);
if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
return (NULL);
while (isdigit((u_char) **layout))
(*layout)++;
if (**layout != 'x')
return (NULL);
(*layout)++;
while (isdigit((u_char) **layout))
(*layout)++;
if (**layout != ',')
return (NULL);
(*layout)++;
while (isdigit((u_char) **layout))
(*layout)++;
if (**layout != ',')
return (NULL);
(*layout)++;
while (isdigit((u_char) **layout))
(*layout)++;
lc = layout_create_cell(lcparent);
lc->sx = sx;
lc->sy = sy;
lc->xoff = xoff;
lc->yoff = yoff;
switch (**layout) {
case ',':
case '}':
case ']':
case '\0':
return (lc);
case '{':
lc->type = LAYOUT_LEFTRIGHT;
break;
case '[':
lc->type = LAYOUT_TOPBOTTOM;
break;
default:
goto fail;
}
do {
(*layout)++;
lcchild = layout_construct(lc, layout);
if (lcchild == NULL)
goto fail;
TAILQ_INSERT_TAIL(&lc->cells, lcchild, entry);
} while (**layout == ',');
switch (lc->type) {
case LAYOUT_LEFTRIGHT:
if (**layout != '}')
goto fail;
break;
case LAYOUT_TOPBOTTOM:
if (**layout != ']')
goto fail;
break;
default:
goto fail;
}
(*layout)++;
return (lc);
fail:
layout_free_cell(lc);
return (NULL);
}

View File

@@ -1,4 +1,4 @@
/* $Id: layout-set.c,v 1.5 2010-02-05 01:29:04 tcunha Exp $ */
/* $Id: layout-set.c,v 1.6 2010-05-14 14:16:37 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,6 +31,7 @@ void layout_set_even_h(struct window *);
void layout_set_even_v(struct window *);
void layout_set_main_h(struct window *);
void layout_set_main_v(struct window *);
void layout_set_tiled(struct window *);
const struct {
const char *name;
@@ -40,6 +41,7 @@ const struct {
{ "even-vertical", layout_set_even_v },
{ "main-horizontal", layout_set_main_h },
{ "main-vertical", layout_set_main_v },
{ "tiled", layout_set_tiled },
};
const char *
@@ -447,3 +449,102 @@ layout_set_main_v(struct window *w)
server_redraw_window(w);
}
void
layout_set_tiled(struct window *w)
{
struct window_pane *wp;
struct layout_cell *lc, *lcrow, *lcchild;
u_int n, width, height, used;
u_int i, j, columns, rows;
layout_print_cell(w->layout_root, __func__, 1);
/* Get number of panes. */
n = window_count_panes(w);
if (n <= 1)
return;
/* How many rows and columns are wanted? */
rows = columns = 1;
while (rows * columns < n) {
rows++;
if (rows * columns < n)
columns++;
}
/* What width and height should they be? */
width = w->sx / columns;
if (width < PANE_MINIMUM + 1)
width = PANE_MINIMUM + 1;
height = w->sy / rows;
if (width < PANE_MINIMUM + 1)
width = PANE_MINIMUM + 1;
/* Free old tree and create a new root. */
layout_free(w);
lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, width * columns, height * rows, 0, 0);
layout_make_node(lc, LAYOUT_TOPBOTTOM);
/* Create a grid of the cells. */
wp = TAILQ_FIRST(&w->panes);
for (j = 0; j < rows; j++) {
/* If this is the last cell, all done. */
if (wp == NULL)
break;
/* Create the new row. */
lcrow = layout_create_cell(lc);
layout_set_size(lcrow, w->sx, height - 1, 0, 0);
TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
/* If only one column, just use the row directly. */
if (n - (j * columns) == 1) {
layout_make_leaf(lcrow, wp);
wp = TAILQ_NEXT(wp, entry);
continue;
}
/* Add in the columns. */
layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
for (i = 0; i < columns; i++) {
/* Create and add a pane cell. */
lcchild = layout_create_cell(lcrow);
layout_set_size(lcchild, width - 1, height - 1, 0, 0);
layout_make_leaf(lcchild, wp);
TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
/* Move to the next cell. */
if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
break;
}
/*
* Adjust the row and columns to fit the full width if
* necessary.
*/
if (i == columns)
i--;
used = ((i + 1) * width) - 1;
if (w->sx <= used)
continue;
lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
layout_resize_adjust(lcchild, LAYOUT_LEFTRIGHT, w->sx - used);
}
/* Adjust the last row height to fit if necessary. */
used = (rows * height) - 1;
if (w->sy > used) {
lcrow = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used);
}
/* Fix cell offsets. */
layout_fix_offsets(lc);
layout_fix_panes(w, w->sx, w->sy);
layout_print_cell(w->layout_root, __func__, 1);
server_redraw_window(w);
}

View File

@@ -1,4 +1,4 @@
/* $Id: layout-string.c,v 1.3 2010-01-08 16:28:04 tcunha Exp $ */
/* $Id: layout-string.c,v 1.4 2010-07-02 02:54:52 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -36,7 +36,6 @@ struct layout_cell *layout_find_right(struct layout_cell *);
struct layout_cell *layout_find_topleft(struct layout_cell *);
struct layout_cell *layout_find_topright(struct layout_cell *);
struct layout_cell *layout_find_bottomleft(struct layout_cell *);
struct layout_cell *layout_find_bottomright(struct layout_cell *);
/* Find the cell; returns NULL if string not understood. */
struct layout_cell *

130
layout.c
View File

@@ -1,4 +1,4 @@
/* $Id: layout.c,v 1.18 2010-01-08 16:31:35 tcunha Exp $ */
/* $Id: layout.c,v 1.19 2010-07-02 02:54:52 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -218,6 +218,27 @@ layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
}
}
/* Count the number of available cells in a layout. */
u_int
layout_count_cells(struct layout_cell *lc)
{
struct layout_cell *lcchild;
u_int n;
switch (lc->type) {
case LAYOUT_WINDOWPANE:
return (1);
case LAYOUT_LEFTRIGHT:
case LAYOUT_TOPBOTTOM:
n = 0;
TAILQ_FOREACH(lcchild, &lc->cells, entry)
n += layout_count_cells(lcchild);
return (n);
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)
@@ -302,6 +323,56 @@ 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)
{
struct layout_cell *lcother, *lcparent;
/*
* If no parent, this is the last pane so window close is imminent and
* there is no need to resize anything.
*/
lcparent = lc->parent;
if (lcparent == NULL) {
layout_free_cell(lc);
*lcroot = NULL;
return;
}
/* Merge the space into the previous or next cell. */
if (lc == TAILQ_FIRST(&lcparent->cells))
lcother = TAILQ_NEXT(lc, entry);
else
lcother = TAILQ_PREV(lc, layout_cells, entry);
if (lcparent->type == LAYOUT_LEFTRIGHT)
layout_resize_adjust(lcother, lcparent->type, lc->sx + 1);
else
layout_resize_adjust(lcother, lcparent->type, lc->sy + 1);
/* Remove this from the parent's list. */
TAILQ_REMOVE(&lcparent->cells, lc, entry);
layout_free_cell(lc);
/*
* If the parent now has one cell, remove the parent from the tree and
* replace it by that cell.
*/
lc = TAILQ_FIRST(&lcparent->cells);
if (TAILQ_NEXT(lc, entry) == NULL) {
TAILQ_REMOVE(&lcparent->cells, lc, entry);
lc->parent = lcparent->parent;
if (lc->parent == NULL) {
lc->xoff = 0; lc->yoff = 0;
*lcroot = lc;
} else
TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry);
layout_free_cell(lcparent);
}
}
void
layout_init(struct window *w)
{
@@ -597,59 +668,16 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size)
return (lcnew);
}
/* Destroy the layout associated with a pane and redistribute the space. */
/* Destroy the cell associated with a pane. */
void
layout_close_pane(struct window_pane *wp)
{
struct layout_cell *lc, *lcother, *lcparent;
lc = wp->layout_cell;
lcparent = lc->parent;
/*
* If no parent, this is the last pane so window close is imminent and
* there is no need to resize anything.
*/
if (lcparent == NULL) {
layout_free_cell(lc);
wp->window->layout_root = NULL;
return;
}
/* Merge the space into the previous or next cell. */
if (lc == TAILQ_FIRST(&lcparent->cells))
lcother = TAILQ_NEXT(lc, entry);
else
lcother = TAILQ_PREV(lc, layout_cells, entry);
if (lcparent->type == LAYOUT_LEFTRIGHT)
layout_resize_adjust(lcother, lcparent->type, lc->sx + 1);
else
layout_resize_adjust(lcother, lcparent->type, lc->sy + 1);
/* Remove this from the parent's list. */
TAILQ_REMOVE(&lcparent->cells, lc, entry);
layout_free_cell(lc);
/*
* If the parent now has one cell, remove the parent from the tree and
* replace it by that cell.
*/
lc = TAILQ_FIRST(&lcparent->cells);
if (TAILQ_NEXT(lc, entry) == NULL) {
TAILQ_REMOVE(&lcparent->cells, lc, entry);
lc->parent = lcparent->parent;
if (lc->parent == NULL) {
lc->xoff = 0; lc->yoff = 0;
wp->window->layout_root = lc;
} else
TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry);
layout_free_cell(lcparent);
}
/* Remove the cell. */
layout_destroy_cell(wp->layout_cell, &wp->window->layout_root);
/* Fix pane offsets and sizes. */
layout_fix_offsets(wp->window->layout_root);
layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
if (wp->window->layout_root != NULL) {
layout_fix_offsets(wp->window->layout_root);
layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
}
}

View File

@@ -1,4 +1,4 @@
/* $Id: mode-key.c,v 1.45 2010-03-08 15:02:07 tcunha Exp $ */
/* $Id: mode-key.c,v 1.46 2010-03-16 17:30:58 micahcowan Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -88,6 +88,10 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
{ MODEKEYCOPY_GOTOLINE, "goto-line" },
{ MODEKEYCOPY_HISTORYBOTTOM, "history-bottom" },
{ MODEKEYCOPY_HISTORYTOP, "history-top" },
{ MODEKEYCOPY_JUMP, "jump-forward" },
{ MODEKEYCOPY_JUMPAGAIN, "jump-again" },
{ MODEKEYCOPY_JUMPREVERSE, "jump-reverse" },
{ MODEKEYCOPY_JUMPBACK, "jump-backward" },
{ MODEKEYCOPY_LEFT, "cursor-left" },
{ MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" },
{ MODEKEYCOPY_MIDDLELINE, "middle-line" },
@@ -177,6 +181,8 @@ struct mode_key_tree mode_key_tree_vi_choice;
const struct mode_key_entry mode_key_vi_copy[] = {
{ ' ', 0, MODEKEYCOPY_STARTSELECTION },
{ '$', 0, MODEKEYCOPY_ENDOFLINE },
{ ',', 0, MODEKEYCOPY_JUMPREVERSE },
{ ';', 0, MODEKEYCOPY_JUMPAGAIN },
{ '/', 0, MODEKEYCOPY_SEARCHDOWN },
{ '0', 0, MODEKEYCOPY_STARTOFLINE },
{ '1', 0, MODEKEYCOPY_STARTNUMBERPREFIX },
@@ -192,6 +198,7 @@ const struct mode_key_entry mode_key_vi_copy[] = {
{ '?', 0, MODEKEYCOPY_SEARCHUP },
{ 'B', 0, MODEKEYCOPY_PREVIOUSSPACE },
{ 'E', 0, MODEKEYCOPY_NEXTSPACEEND },
{ 'F', 0, MODEKEYCOPY_JUMPBACK },
{ 'G', 0, MODEKEYCOPY_HISTORYBOTTOM },
{ 'H', 0, MODEKEYCOPY_TOPLINE },
{ 'J', 0, MODEKEYCOPY_SCROLLDOWN },
@@ -213,6 +220,7 @@ const struct mode_key_entry mode_key_vi_copy[] = {
{ '^', 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 },
@@ -290,6 +298,8 @@ 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 },
@@ -301,6 +311,8 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
{ '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 },
{ '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION },
@@ -319,6 +331,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
{ '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL },
{ 'N', 0, MODEKEYCOPY_SEARCHREVERSE },
{ '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 },

26
paste.c
View File

@@ -1,4 +1,4 @@
/* $Id: paste.c,v 1.13 2009-12-04 22:14:47 tcunha Exp $ */
/* $Id: paste.c,v 1.15 2010-06-22 23:36:54 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -156,3 +156,27 @@ paste_replace(struct paste_stack *ps, u_int idx, char *data, size_t size)
return (0);
}
/* Convert a buffer into a visible string. */
char *
paste_print(struct paste_buffer *pb, size_t width)
{
char *buf;
size_t len, used;
if (width < 3)
width = 3;
buf = xmalloc(width * 4 + 1);
len = pb->size;
if (len > width)
len = width;
used = strvisx(buf, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL);
if (pb->size > width || used > width) {
buf[width - 3] = '\0';
strlcat(buf, "...", width);
}
return (buf);
}

View File

@@ -1,4 +1,4 @@
/* $Id: resize.c,v 1.24 2009-09-25 17:47:42 tcunha Exp $ */
/* $Id: resize.c,v 1.25 2010-06-22 23:26:18 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -105,7 +105,7 @@ recalculate_sizes(void)
if (flag)
has = s->curw->window == w;
else
has = session_has(s, w);
has = session_has(s, w) != NULL;
if (has) {
if (s->sx < ssx)
ssx = s->sx;

View File

@@ -1,4 +1,4 @@
/* $Id: screen-write.c,v 1.88 2009-12-04 22:14:47 tcunha Exp $ */
/* $Id: screen-write.c,v 1.90 2010-06-16 18:09:23 micahcowan Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -23,7 +23,7 @@
#include "tmux.h"
void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *, int);
void screen_write_overwrite(struct screen_write_ctx *);
void screen_write_overwrite(struct screen_write_ctx *, u_int);
int screen_write_combine(
struct screen_write_ctx *, const struct utf8_data *);
@@ -1009,17 +1009,18 @@ screen_write_cell(struct screen_write_ctx *ctx,
}
/* Check this will fit on the current line and wrap if not. */
if (s->cx > screen_size_x(s) - width) {
if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) {
screen_write_linefeed(ctx, 1);
s->cx = 0; /* carriage return */
}
/* Sanity checks. */
if (s->cx > screen_size_x(s) - 1 || s->cy > screen_size_y(s) - 1)
if (((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - 1)
|| s->cy > screen_size_y(s) - 1)
return;
/* Handle overwriting of UTF-8 characters. */
screen_write_overwrite(ctx);
screen_write_overwrite(ctx, width);
/*
* If the new character is UTF-8 wide, fill in padding cells. Have
@@ -1122,12 +1123,11 @@ screen_write_combine(
* by the same character.
*/
void
screen_write_overwrite(struct screen_write_ctx *ctx)
screen_write_overwrite(struct screen_write_ctx *ctx, u_int width)
{
struct screen *s = ctx->s;
struct grid *gd = s->grid;
const struct grid_cell *gc;
const struct grid_utf8 *gu;
u_int xx;
gc = grid_view_peek_cell(gd, s->cx, s->cy);
@@ -1147,30 +1147,17 @@ screen_write_overwrite(struct screen_write_ctx *ctx)
/* Overwrite the character at the start of this padding. */
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
}
/* Overwrite following padding cells. */
xx = s->cx;
while (++xx < screen_size_x(s)) {
gc = grid_view_peek_cell(gd, xx, s->cy);
if (!(gc->flags & GRID_FLAG_PADDING))
break;
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
}
} else if (gc->flags & GRID_FLAG_UTF8) {
gu = grid_view_peek_utf8(gd, s->cx, s->cy);
if (gu->width > 1) {
/*
* An UTF-8 wide cell; overwrite following padding
* cells only.
*/
xx = s->cx;
while (++xx < screen_size_x(s)) {
gc = grid_view_peek_cell(gd, xx, s->cy);
if (!(gc->flags & GRID_FLAG_PADDING))
break;
grid_view_set_cell(
gd, xx, s->cy, &grid_default_cell);
}
}
/*
* Overwrite any padding cells that belong to a UTF-8 character
* we'll be overwriting with the current character.
*/
xx = s->cx + width - 1;
while (++xx < screen_size_x(s)) {
gc = grid_view_peek_cell(gd, xx, s->cy);
if (!(gc->flags & GRID_FLAG_PADDING))
break;
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
}
}

View File

@@ -1,4 +1,4 @@
/* $Id: screen.c,v 1.99 2010-02-08 18:13:17 tcunha Exp $ */
/* $Id: screen.c,v 1.101 2010-04-06 22:01:32 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
@@ -30,9 +31,14 @@ void screen_resize_y(struct screen *, u_int);
void
screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
{
char hn[MAXHOSTNAMELEN];
s->grid = grid_create(sx, sy, hlimit);
s->title = xstrdup("");
if (gethostname(hn, MAXHOSTNAMELEN) == 0)
s->title = xstrdup(hn);
else
s->title = xstrdup("");
s->tabs = NULL;
@@ -49,7 +55,7 @@ screen_reinit(struct screen *s)
s->rupper = 0;
s->rlower = screen_size_y(s) - 1;
s->mode = MODE_CURSOR;
s->mode = MODE_CURSOR | MODE_WRAP;
screen_reset_tabs(s);

View File

@@ -1,4 +1,4 @@
/* $Id: server-client.c,v 1.31 2010-02-08 18:27:34 tcunha Exp $ */
/* $Id: server-client.c,v 1.35 2010-07-17 14:36:40 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -68,6 +68,10 @@ server_client_create(int fd)
ARRAY_INIT(&c->prompt_hdata);
c->stdin_file = NULL;
c->stdout_file = NULL;
c->stderr_file = NULL;
c->tty.fd = -1;
c->title = NULL;
@@ -117,6 +121,13 @@ server_client_lost(struct client *c)
if (c->flags & CLIENT_TERMINAL)
tty_free(&c->tty);
if (c->stdin_file != NULL)
fclose(c->stdin_file);
if (c->stdout_file != NULL)
fclose(c->stdout_file);
if (c->stderr_file != NULL)
fclose(c->stderr_file);
screen_free(&c->status);
job_tree_free(&c->status_jobs);
@@ -299,7 +310,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
server_redraw_window_borders(w);
wp = w->active;
}
window_pane_mouse(wp, c, mouse);
window_pane_mouse(wp, c->session, mouse);
return;
}
@@ -321,7 +332,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
/* Try as a non-prefix key binding. */
if ((bd = key_bindings_lookup(key)) == NULL) {
if (!(c->flags & CLIENT_READONLY))
window_pane_key(wp, c, key);
window_pane_key(wp, c->session, key);
} else
key_bindings_dispatch(bd, c);
}
@@ -337,7 +348,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
if (isprefix)
c->flags |= CLIENT_PREFIX;
else if (!(c->flags & CLIENT_READONLY))
window_pane_key(wp, c, key);
window_pane_key(wp, c->session, key);
}
return;
}
@@ -348,7 +359,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
if (isprefix)
c->flags |= CLIENT_PREFIX;
else if (!(c->flags & CLIENT_READONLY))
window_pane_key(wp, c, key);
window_pane_key(wp, c->session, key);
return;
}
@@ -554,15 +565,39 @@ server_client_msg_dispatch(struct client *c)
fatalx("MSG_IDENTIFY missing fd");
memcpy(&identifydata, imsg.data, sizeof identifydata);
c->stdin_file = fdopen(imsg.fd, "r");
if (c->stdin_file == NULL)
fatal("fdopen(stdin) failed");
server_client_msg_identify(c, &identifydata, imsg.fd);
break;
case MSG_STDOUT:
if (datalen != 0)
fatalx("bad MSG_STDOUT size");
if (imsg.fd == -1)
fatalx("MSG_STDOUT missing fd");
c->stdout_file = fdopen(imsg.fd, "w");
if (c->stdout_file == NULL)
fatal("fdopen(stdout) failed");
break;
case MSG_STDERR:
if (datalen != 0)
fatalx("bad MSG_STDERR size");
if (imsg.fd == -1)
fatalx("MSG_STDERR missing fd");
c->stderr_file = fdopen(imsg.fd, "w");
if (c->stderr_file == NULL)
fatal("fdopen(stderr) failed");
break;
case MSG_RESIZE:
if (datalen != 0)
fatalx("bad MSG_RESIZE size");
tty_resize(&c->tty);
recalculate_sizes();
server_redraw_client(c);
if (tty_resize(&c->tty)) {
recalculate_sizes();
server_redraw_client(c);
}
break;
case MSG_EXITING:
if (datalen != 0)
@@ -620,55 +655,58 @@ server_client_msg_dispatch(struct client *c)
void printflike2
server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
{
struct msg_print_data data;
va_list ap;
va_list ap;
va_start(ap, fmt);
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
vfprintf(ctx->cmdclient->stderr_file, fmt, ap);
va_end(ap);
server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data);
fputc('\n', ctx->cmdclient->stderr_file);
fflush(ctx->cmdclient->stderr_file);
ctx->cmdclient->retcode = 1;
}
/* Callback to send print message to client. */
void printflike2
server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...)
{
struct msg_print_data data;
va_list ap;
va_list ap;
va_start(ap, fmt);
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
vfprintf(ctx->cmdclient->stdout_file, fmt, ap);
va_end(ap);
server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
fputc('\n', ctx->cmdclient->stdout_file);
fflush(ctx->cmdclient->stdout_file);
}
/* Callback to send print message to client, if not quiet. */
void printflike2
server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...)
{
struct msg_print_data data;
va_list ap;
va_list ap;
if (options_get_number(&global_options, "quiet"))
return;
va_start(ap, fmt);
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
vfprintf(ctx->cmdclient->stdout_file, fmt, ap);
va_end(ap);
server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
fputc('\n', ctx->cmdclient->stderr_file);
fflush(ctx->cmdclient->stdout_file);
}
/* Handle command message. */
void
server_client_msg_command(struct client *c, struct msg_command_data *data)
{
struct cmd_ctx ctx;
struct cmd_list *cmdlist = NULL;
int argc;
char **argv, *cause;
struct cmd_ctx ctx;
struct cmd_list *cmdlist = NULL;
struct msg_exit_data exitdata;
int argc;
char **argv, *cause;
ctx.error = server_client_msg_error;
ctx.print = server_client_msg_print;
@@ -699,15 +737,18 @@ server_client_msg_command(struct client *c, struct msg_command_data *data)
}
cmd_free_argv(argc, argv);
if (cmd_list_exec(cmdlist, &ctx) != 1)
server_write_client(c, MSG_EXIT, NULL, 0);
if (cmd_list_exec(cmdlist, &ctx) != 1) {
exitdata.retcode = c->retcode;
server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata);
}
cmd_list_free(cmdlist);
return;
error:
if (cmdlist != NULL)
cmd_list_free(cmdlist);
server_write_client(c, MSG_EXIT, NULL, 0);
exitdata.retcode = c->retcode;
server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata);
}
/* Handle identify message. */
@@ -715,13 +756,19 @@ void
server_client_msg_identify(
struct client *c, struct msg_identify_data *data, int fd)
{
int tty_fd;
c->cwd = NULL;
data->cwd[(sizeof data->cwd) - 1] = '\0';
if (*data->cwd != '\0')
c->cwd = xstrdup(data->cwd);
if (!isatty(fd))
return;
if ((tty_fd = dup(fd)) == -1)
fatal("dup failed");
data->term[(sizeof data->term) - 1] = '\0';
tty_init(&c->tty, fd, data->term);
tty_init(&c->tty, tty_fd, data->term);
if (data->flags & IDENTIFY_UTF8)
c->tty.flags |= TTY_UTF8;
if (data->flags & IDENTIFY_256COLOURS)

View File

@@ -1,4 +1,4 @@
/* $Id: server-fn.c,v 1.102 2010-01-25 17:13:43 tcunha Exp $ */
/* $Id: server-fn.c,v 1.108 2010-07-02 02:45:52 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,7 +24,8 @@
#include "tmux.h"
void server_callback_identify(int, short, void *);
struct session *server_next_session(struct session *);
void server_callback_identify(int, short, void *);
void
server_fill_environ(struct session *s, struct environ *env)
@@ -42,15 +43,6 @@ server_fill_environ(struct session *s, struct environ *env)
environ_set(env, "TERM", term);
}
void
server_write_error(struct client *c, const char *msg)
{
struct msg_print_data printdata;
strlcpy(printdata.msg, msg, sizeof printdata.msg);
server_write_client(c, MSG_ERROR, &printdata, sizeof printdata);
}
void
server_write_client(
struct client *c, enum msgtype type, const void *buf, size_t len)
@@ -193,7 +185,7 @@ server_status_window(struct window *w)
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s != NULL && session_has(s, w))
if (s != NULL && session_has(s, w) != NULL)
server_status_session(s);
}
}
@@ -258,7 +250,7 @@ server_kill_window(struct window *w)
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL || !session_has(s, w))
if (s == NULL || session_has(s, w) == NULL)
continue;
while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) {
if (session_detach(s, wl)) {
@@ -295,7 +287,7 @@ server_link_window(struct session *src, struct winlink *srcwl,
* Can't use session_detach as it will destroy session
* if this makes it empty.
*/
session_alert_cancel(dst, dstwl);
dstwl->flags &= ~WINLINK_ALERTFLAGS;
winlink_stack_remove(&dst->lastw, dstwl);
winlink_remove(&dst->windows, dstwl);
@@ -334,9 +326,11 @@ server_destroy_pane(struct window_pane *wp)
{
struct window *w = wp->window;
close(wp->fd);
bufferevent_free(wp->event);
wp->fd = -1;
if (wp->fd != -1) {
close(wp->fd);
bufferevent_free(wp->event);
wp->fd = -1;
}
if (options_get_number(&w->options, "remain-on-exit"))
return;
@@ -365,19 +359,49 @@ server_destroy_session_group(struct session *s)
}
}
struct session *
server_next_session(struct session *s)
{
struct session *s_loop, *s_out;
u_int i;
s_out = NULL;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s_loop = ARRAY_ITEM(&sessions, i);
if (s_loop == s)
continue;
if (s_out == NULL ||
timercmp(&s_loop->activity_time, &s_out->activity_time, <))
s_out = s_loop;
}
return (s_out);
}
void
server_destroy_session(struct session *s)
{
struct client *c;
struct session *s_new;
u_int i;
if (!options_get_number(&s->options, "detach-on-destroy"))
s_new = server_next_session(s);
else
s_new = NULL;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != s)
continue;
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
if (s_new == NULL) {
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
} else {
c->session = s_new;
server_redraw_client(c);
}
}
recalculate_sizes();
}
void

View File

@@ -1,4 +1,4 @@
/* $Id: server-window.c,v 1.14 2010-02-26 13:26:44 tcunha Exp $ */
/* $Id: server-window.c,v 1.15 2010-06-22 23:26:18 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,10 +24,10 @@
#include "tmux.h"
int server_window_backoff(struct window_pane *);
int server_window_check_bell(struct session *, struct window *);
int server_window_check_activity(struct session *, struct window *);
int server_window_check_bell(struct session *, struct winlink *);
int server_window_check_activity(struct session *, struct winlink *);
int server_window_check_content(
struct session *, struct window *, struct window_pane *);
struct session *, struct winlink *, struct window_pane *);
/* Check if this window should suspend reading. */
int
@@ -59,6 +59,7 @@ void
server_window_loop(void)
{
struct window *w;
struct winlink *wl;
struct window_pane *wp;
struct session *s;
u_int i, j;
@@ -81,33 +82,37 @@ server_window_loop(void)
for (j = 0; j < ARRAY_LENGTH(&sessions); j++) {
s = ARRAY_ITEM(&sessions, j);
if (s == NULL || !session_has(s, w))
if (s == NULL)
continue;
wl = session_has(s, w);
if (wl == NULL)
continue;
if (server_window_check_bell(s, w) ||
server_window_check_activity(s, w))
if (server_window_check_bell(s, wl) ||
server_window_check_activity(s, wl))
server_status_session(s);
TAILQ_FOREACH(wp, &w->panes, entry)
server_window_check_content(s, w, wp);
server_window_check_content(s, wl, wp);
}
w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT);
w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY);
}
}
/* Check for bell in window. */
int
server_window_check_bell(struct session *s, struct window *w)
server_window_check_bell(struct session *s, struct winlink *wl)
{
struct client *c;
struct window *w = wl->window;
u_int i;
int action, visual;
if (!(w->flags & WINDOW_BELL))
if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL)
return (0);
if (s->curw == wl)
return (0);
if (session_alert_has_window(s, w, WINDOW_BELL))
return (0);
session_alert_add(s, w, WINDOW_BELL);
wl->flags |= WINLINK_BELL;
action = options_get_number(&s->options, "bell-action");
switch (action) {
@@ -155,25 +160,22 @@ server_window_check_bell(struct session *s, struct window *w)
/* Check for activity in window. */
int
server_window_check_activity(struct session *s, struct window *w)
server_window_check_activity(struct session *s, struct winlink *wl)
{
struct client *c;
struct window *w = wl->window;
u_int i;
if (!(w->flags & WINDOW_ACTIVITY))
if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY)
return (0);
if (s->curw->window == w)
if (s->curw == wl)
return (0);
if (!options_get_number(&w->options, "monitor-activity"))
return (0);
if (session_alert_has_window(s, w, WINDOW_ACTIVITY))
return (0);
session_alert_add(s, w, WINDOW_ACTIVITY);
wl->flags |= WINLINK_ACTIVITY;
if (s->flags & SESSION_UNATTACHED)
return (0);
if (options_get_number(&s->options, "visual-activity")) {
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
@@ -190,31 +192,28 @@ server_window_check_activity(struct session *s, struct window *w)
/* Check for content change in window. */
int
server_window_check_content(
struct session *s, struct window *w, struct window_pane *wp)
struct session *s, struct winlink *wl, struct window_pane *wp)
{
struct client *c;
struct window *w = wl->window;
u_int i;
char *found, *ptr;
if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */
/* Activity flag must be set for new content. */
if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_CONTENT)
return (0);
if (s->curw->window == w)
if (s->curw == wl)
return (0);
ptr = options_get_string(&w->options, "monitor-content");
if (ptr == NULL || *ptr == '\0')
return (0);
if (session_alert_has_window(s, w, WINDOW_CONTENT))
return (0);
if ((found = window_pane_search(wp, ptr, NULL)) == NULL)
return (0);
xfree(found);
session_alert_add(s, w, WINDOW_CONTENT);
if (s->flags & SESSION_UNATTACHED)
return (0);
wl->flags |= WINLINK_CONTENT;
if (options_get_number(&s->options, "visual-content")) {
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);

View File

@@ -1,4 +1,4 @@
/* $Id: server.c,v 1.235 2010-02-08 18:29:32 tcunha Exp $ */
/* $Id: server.c,v 1.242 2010-06-22 23:21:39 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -48,9 +48,6 @@ struct clients dead_clients;
int server_fd;
int server_shutdown;
struct event server_ev_accept;
struct event server_ev_sigterm;
struct event server_ev_sigusr1;
struct event server_ev_sigchld;
struct event server_ev_second;
int server_create_socket(void);
@@ -88,7 +85,7 @@ server_create_socket(void)
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
fatal("socket failed");
mask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
fatal("bind failed");
umask(mask);
@@ -113,7 +110,7 @@ int
server_start(char *path)
{
struct window_pane *wp;
int pair[2], retval;
int pair[2];
char *cause;
struct timeval tv;
u_int i;
@@ -143,6 +140,11 @@ server_start(char *path)
if (daemon(1, 0) != 0)
fatal("daemon failed");
/* event_init() was called in our parent, need to reinit. */
if (event_reinit(ev_base) != 0)
fatal("event_reinit failed");
clear_signals();
logfile("server");
log_debug("server started, pid %ld", (long) getpid());
@@ -166,26 +168,9 @@ server_start(char *path)
setproctitle("server (%s)", rpathbuf);
#endif
#ifdef HAVE_BROKEN_KQUEUE
if (setenv("EVENT_NOKQUEUE", "1", 1) != 0)
fatal("setenv failed");
#endif
#ifdef HAVE_BROKEN_POLL
if (setenv("EVENT_NOPOLL", "1", 1) != 0)
fatal("setenv failed");
#endif
event_init();
#ifdef HAVE_BROKEN_KQUEUE
unsetenv("EVENT_NOKQUEUE");
#endif
#ifdef HAVE_BROKEN_POLL
unsetenv("EVENT_NOPOLL");
#endif
server_fd = server_create_socket();
server_client_create(pair[1]);
retval = 0;
if (access(SYSTEM_CFG, R_OK) == 0)
load_cfg(SYSTEM_CFG, NULL, &cfg_causes);
else if (errno != ENOENT) {
@@ -201,10 +186,11 @@ server_start(char *path)
*/
if (!ARRAY_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) {
wp = ARRAY_FIRST(&sessions)->curw->window->active;
window_pane_set_mode(wp, &window_more_mode);
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp);
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
cause = ARRAY_ITEM(&cfg_causes, i);
window_more_add(wp, "%s", cause);
window_copy_add(wp, "%s", cause);
xfree(cause);
}
ARRAY_FREE(&cfg_causes);
@@ -220,7 +206,7 @@ server_start(char *path)
evtimer_set(&server_ev_second, server_second_callback, NULL);
evtimer_add(&server_ev_second, &tv);
server_signal_set();
set_signals(server_signal_callback);
server_loop();
exit(0);
}
@@ -328,9 +314,9 @@ server_update_socket(void)
if (n != last) {
last = n;
if (n != 0)
chmod(socket_path, S_IRWXU);
chmod(socket_path, S_IRWXU|S_IRWXG);
else
chmod(socket_path, S_IRUSR|S_IWUSR);
chmod(socket_path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
}
}
@@ -359,61 +345,6 @@ server_accept_callback(int fd, short events, unused void *data)
server_client_create(newfd);
}
/* Set up server signal handling. */
void
server_signal_set(void)
{
struct sigaction sigact;
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGHUP, &sigact, NULL) != 0)
fatal("sigaction failed");
signal_set(&server_ev_sigchld, SIGCHLD, server_signal_callback, NULL);
signal_add(&server_ev_sigchld, NULL);
signal_set(&server_ev_sigterm, SIGTERM, server_signal_callback, NULL);
signal_add(&server_ev_sigterm, NULL);
signal_set(&server_ev_sigusr1, SIGUSR1, server_signal_callback, NULL);
signal_add(&server_ev_sigusr1, NULL);
}
/* Destroy server signal events. */
void
server_signal_clear(void)
{
struct sigaction sigact;
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_DFL;
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGHUP, &sigact, NULL) != 0)
fatal("sigaction failed");
signal_del(&server_ev_sigchld);
signal_del(&server_ev_sigterm);
signal_del(&server_ev_sigusr1);
}
/* Signal handler. */
/* ARGSUSED */
void

138
session.c
View File

@@ -1,4 +1,4 @@
/* $Id: session.c,v 1.74 2009-12-26 23:45:21 tcunha Exp $ */
/* $Id: session.c,v 1.77 2010-07-02 02:49:19 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,71 +31,8 @@ struct sessions sessions;
struct sessions dead_sessions;
struct session_groups session_groups;
struct winlink *session_next_activity(struct session *, struct winlink *);
struct winlink *session_previous_activity(struct session *, struct winlink *);
void
session_alert_cancel(struct session *s, struct winlink *wl)
{
struct session_alert *sa, *sb;
sa = SLIST_FIRST(&s->alerts);
while (sa != NULL) {
sb = sa;
sa = SLIST_NEXT(sa, entry);
if (wl == NULL || sb->wl == wl) {
SLIST_REMOVE(&s->alerts, sb, session_alert, entry);
xfree(sb);
}
}
}
void
session_alert_add(struct session *s, struct window *w, int type)
{
struct session_alert *sa;
struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows) {
if (wl == s->curw)
continue;
if (wl->window == w &&
!session_alert_has(s, wl, type)) {
sa = xmalloc(sizeof *sa);
sa->wl = wl;
sa->type = type;
SLIST_INSERT_HEAD(&s->alerts, sa, entry);
}
}
}
int
session_alert_has(struct session *s, struct winlink *wl, int type)
{
struct session_alert *sa;
SLIST_FOREACH(sa, &s->alerts, entry) {
if (sa->wl == wl && sa->type == type)
return (1);
}
return (0);
}
int
session_alert_has_window(struct session *s, struct window *w, int type)
{
struct session_alert *sa;
SLIST_FOREACH(sa, &s->alerts, entry) {
if (sa->wl->window == w && sa->type == type)
return (1);
}
return (0);
}
struct winlink *session_next_alert(struct winlink *);
struct winlink *session_previous_alert(struct winlink *);
/* Find session by name. */
struct session *
@@ -130,10 +67,11 @@ session_create(const char *name, const char *cmd, const char *cwd,
fatal("gettimeofday failed");
memcpy(&s->activity_time, &s->creation_time, sizeof s->activity_time);
s->cwd = xstrdup(cwd);
s->curw = NULL;
TAILQ_INIT(&s->lastw);
RB_INIT(&s->windows);
SLIST_INIT(&s->alerts);
paste_init_stack(&s->buffers);
@@ -196,7 +134,6 @@ session_destroy(struct session *s)
xfree(s->tio);
session_group_remove(s);
session_alert_cancel(s, NULL);
environ_free(&s->environ);
options_free(&s->options);
paste_free_stack(&s->buffers);
@@ -206,6 +143,7 @@ session_destroy(struct session *s)
while (!RB_EMPTY(&s->windows))
winlink_remove(&s->windows, RB_ROOT(&s->windows));
xfree(s->cwd);
xfree(s->name);
for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) {
@@ -284,7 +222,7 @@ session_detach(struct session *s, struct winlink *wl)
session_last(s) != 0 && session_previous(s, 0) != 0)
session_next(s, 0);
session_alert_cancel(s, wl);
wl->flags &= ~WINLINK_ALERTFLAGS;
winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl);
session_group_synchronize_from(s);
@@ -296,27 +234,23 @@ session_detach(struct session *s, struct winlink *wl)
}
/* Return if session has window. */
int
struct winlink *
session_has(struct session *s, struct window *w)
{
struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows) {
if (wl->window == w)
return (1);
return (wl);
}
return (0);
return (NULL);
}
struct winlink *
session_next_activity(struct session *s, struct winlink *wl)
session_next_alert(struct winlink *wl)
{
while (wl != NULL) {
if (session_alert_has(s, wl, WINDOW_BELL))
break;
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
break;
if (session_alert_has(s, wl, WINDOW_CONTENT))
if (wl->flags & WINLINK_ALERTFLAGS)
break;
wl = winlink_next(wl);
}
@@ -325,7 +259,7 @@ session_next_activity(struct session *s, struct winlink *wl)
/* Move session to next window. */
int
session_next(struct session *s, int activity)
session_next(struct session *s, int alert)
{
struct winlink *wl;
@@ -333,11 +267,11 @@ session_next(struct session *s, int activity)
return (-1);
wl = winlink_next(s->curw);
if (activity)
wl = session_next_activity(s, wl);
if (alert)
wl = session_next_alert(wl);
if (wl == NULL) {
wl = RB_MIN(winlinks, &s->windows);
if (activity && ((wl = session_next_activity(s, wl)) == NULL))
if (alert && ((wl = session_next_alert(wl)) == NULL))
return (-1);
}
if (wl == s->curw)
@@ -345,19 +279,15 @@ session_next(struct session *s, int activity)
winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw);
s->curw = wl;
session_alert_cancel(s, wl);
wl->flags &= ~WINLINK_ALERTFLAGS;
return (0);
}
struct winlink *
session_previous_activity(struct session *s, struct winlink *wl)
session_previous_alert(struct winlink *wl)
{
while (wl != NULL) {
if (session_alert_has(s, wl, WINDOW_BELL))
break;
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
break;
if (session_alert_has(s, wl, WINDOW_CONTENT))
if (wl->flags & WINLINK_ALERTFLAGS)
break;
wl = winlink_previous(wl);
}
@@ -366,7 +296,7 @@ session_previous_activity(struct session *s, struct winlink *wl)
/* Move session to previous window. */
int
session_previous(struct session *s, int activity)
session_previous(struct session *s, int alert)
{
struct winlink *wl;
@@ -374,11 +304,11 @@ session_previous(struct session *s, int activity)
return (-1);
wl = winlink_previous(s->curw);
if (activity)
wl = session_previous_activity(s, wl);
if (alert)
wl = session_previous_alert(wl);
if (wl == NULL) {
wl = RB_MAX(winlinks, &s->windows);
if (activity && (wl = session_previous_activity(s, wl)) == NULL)
if (alert && (wl = session_previous_alert(wl)) == NULL)
return (-1);
}
if (wl == s->curw)
@@ -386,7 +316,7 @@ session_previous(struct session *s, int activity)
winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw);
s->curw = wl;
session_alert_cancel(s, wl);
wl->flags &= ~WINLINK_ALERTFLAGS;
return (0);
}
@@ -404,7 +334,7 @@ session_select(struct session *s, int idx)
winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw);
s->curw = wl;
session_alert_cancel(s, wl);
wl->flags &= ~WINLINK_ALERTFLAGS;
return (0);
}
@@ -423,7 +353,7 @@ session_last(struct session *s)
winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw);
s->curw = wl;
session_alert_cancel(s, wl);
wl->flags &= ~WINLINK_ALERTFLAGS;
return (0);
}
@@ -540,7 +470,6 @@ session_group_synchronize1(struct session *target, struct session *s)
struct winlinks old_windows, *ww;
struct winlink_stack old_lastw;
struct winlink *wl, *wl2;
struct session_alert *sa;
/* Don't do anything if the session is empty (it'll be destroyed). */
ww = &target->windows;
@@ -558,8 +487,10 @@ session_group_synchronize1(struct session *target, struct session *s)
RB_INIT(&s->windows);
/* Link all the windows from the target. */
RB_FOREACH(wl, winlinks, ww)
winlink_add(&s->windows, wl->window, wl->idx);
RB_FOREACH(wl, winlinks, ww) {
wl2 = winlink_add(&s->windows, wl->window, wl->idx);
wl2->flags |= wl->flags & WINLINK_ALERTFLAGS;
}
/* Fix up the current window. */
if (s->curw != NULL)
@@ -576,15 +507,6 @@ session_group_synchronize1(struct session *target, struct session *s)
TAILQ_INSERT_TAIL(&s->lastw, wl2, sentry);
}
/* And update the alerts list. */
SLIST_FOREACH(sa, &s->alerts, entry) {
wl = winlink_find_by_index(&s->windows, sa->wl->idx);
if (wl == NULL)
session_alert_cancel(s, sa->wl);
else
sa->wl = wl;
}
/* Then free the old winlinks list. */
while (!RB_EMPTY(&old_windows)) {
wl = RB_ROOT(&old_windows);

88
signal.c Normal file
View File

@@ -0,0 +1,88 @@
/* $Id: signal.c,v 1.2 2010-05-14 14:35:26 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
* Copyright (c) 2010 Romain Francoise <rfrancoise@debian.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include <signal.h>
#include "tmux.h"
struct event ev_sighup;
struct event ev_sigchld;
struct event ev_sigcont;
struct event ev_sigterm;
struct event ev_sigusr1;
struct event ev_sigwinch;
void
set_signals(void(*handler)(int, short, unused void *))
{
struct sigaction sigact;
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
signal_set(&ev_sighup, SIGHUP, handler, NULL);
signal_add(&ev_sighup, NULL);
signal_set(&ev_sigchld, SIGCHLD, handler, NULL);
signal_add(&ev_sigchld, NULL);
signal_set(&ev_sigcont, SIGCONT, handler, NULL);
signal_add(&ev_sigcont, NULL);
signal_set(&ev_sigterm, SIGTERM, handler, NULL);
signal_add(&ev_sigterm, NULL);
signal_set(&ev_sigusr1, SIGUSR1, handler, NULL);
signal_add(&ev_sigusr1, NULL);
signal_set(&ev_sigwinch, SIGWINCH, handler, NULL);
signal_add(&ev_sigwinch, NULL);
}
void
clear_signals(void)
{
struct sigaction sigact;
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_DFL;
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
event_del(&ev_sighup);
event_del(&ev_sigchld);
event_del(&ev_sigcont);
event_del(&ev_sigterm);
event_del(&ev_sigusr1);
event_del(&ev_sigwinch);
}

View File

@@ -1,4 +1,4 @@
/* $Id: status.c,v 1.144 2010-03-10 13:41:13 nicm Exp $ */
/* $Id: status.c,v 1.149 2010-06-22 23:26:18 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -35,7 +35,6 @@ char *status_redraw_get_right(
struct client *, time_t, int, struct grid_cell *, size_t *);
char *status_job(struct client *, char **);
void status_job_callback(struct job *);
size_t status_width(struct client *, struct winlink *, time_t);
char *status_print(
struct client *, struct winlink *, time_t, struct grid_cell *);
void status_replace1(struct client *,
@@ -249,25 +248,15 @@ status_redraw(struct client *c)
*/
offset = 0;
RB_FOREACH(wl, winlinks, &s->windows) {
if (larrow == 1 && offset < wlstart) {
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
larrow = -1;
else if (session_alert_has(s, wl, WINDOW_BELL))
larrow = -1;
else if (session_alert_has(s, wl, WINDOW_CONTENT))
larrow = -1;
}
if (wl->flags & WINLINK_ALERTFLAGS &&
larrow == 1 && offset < wlstart)
larrow = -1;
offset += wl->status_width;
if (rarrow == 1 && offset > wlstart + wlwidth) {
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
rarrow = -1;
else if (session_alert_has(s, wl, WINDOW_BELL))
rarrow = -1;
else if (session_alert_has(s, wl, WINDOW_CONTENT))
rarrow = -1;
}
if (wl->flags & WINLINK_ALERTFLAGS &&
rarrow == 1 && offset > wlstart + wlwidth)
rarrow = -1;
}
draw:
@@ -400,11 +389,11 @@ status_replace1(struct client *c,struct winlink *wl,
goto do_replace;
case 'F':
tmp[0] = ' ';
if (session_alert_has(s, wl, WINDOW_CONTENT))
if (wl->flags & WINLINK_CONTENT)
tmp[0] = '+';
else if (session_alert_has(s, wl, WINDOW_BELL))
else if (wl->flags & WINLINK_BELL)
tmp[0] = '!';
else if (session_alert_has(s, wl, WINDOW_ACTIVITY))
else if (wl->flags & WINLINK_ACTIVITY)
tmp[0] = '#';
else if (wl == s->curw)
tmp[0] = '*';
@@ -560,30 +549,6 @@ status_job_callback(struct job *job)
job->data = xstrdup(line);
}
/* Calculate winlink status line entry width. */
size_t
status_width(struct client *c, struct winlink *wl, time_t t)
{
struct options *oo = &wl->window->options;
struct session *s = c->session;
const char *fmt;
char *text;
size_t size;
int utf8flag;
utf8flag = options_get_number(&s->options, "status-utf8");
fmt = options_get_string(&wl->window->options, "window-status-format");
if (wl == s->curw)
fmt = options_get_string(oo, "window-status-current-format");
text = status_replace(c, wl, fmt, t, 1);
size = screen_write_cstrlen(utf8flag, "%s", text);
xfree(text);
return (size);
}
/* Return winlink status line entry and adjust gc as necessary. */
char *
status_print(
@@ -618,10 +583,17 @@ status_print(
fmt = options_get_string(oo, "window-status-current-format");
}
if (session_alert_has(s, wl, WINDOW_ACTIVITY) ||
session_alert_has(s, wl, WINDOW_BELL) ||
session_alert_has(s, wl, WINDOW_CONTENT))
gc->attr ^= GRID_ATTR_REVERSE;
if (wl->flags & WINLINK_ALERTFLAGS) {
fg = options_get_number(oo, "window-status-alert-fg");
if (fg != 8)
colour_set_fg(gc, fg);
bg = options_get_number(oo, "window-status-alert-bg");
if (bg != 8)
colour_set_bg(gc, bg);
attr = options_get_number(oo, "window-status-alert-attr");
if (attr != 0)
gc->attr = attr;
}
text = status_replace(c, wl, fmt, t, 1);
return (text);
@@ -1071,7 +1043,7 @@ status_prompt_key(struct client *c, int key)
status_prompt_clear(c);
break;
case MODEKEY_OTHER:
if (key < 32 || key == 127)
if ((key & 0xff00) != 0 || key < 32 || key == 127)
break;
c->prompt_buffer = xrealloc(c->prompt_buffer, 1, size + 2);

347
tmux.1
View File

@@ -1,4 +1,4 @@
.\" $Id: tmux.1,v 1.237 2010-03-08 15:02:07 tcunha Exp $
.\" $Id: tmux.1,v 1.264 2010-07-17 14:39:01 tcunha Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: March 2 2010 $
.Dd $Mdocdate: July 15 2010 $
.Dt TMUX 1
.Os
.Sh NAME
@@ -131,10 +131,6 @@ commands which are executed in sequence when the server is first started.
If a command in the configuration file fails,
.Nm
will report an error and exit without executing further commands.
.It Fl l
Behave as a login shell.
This flag currently has no effect and is for compatibility with other shells
when using tmux as a login shell.
.It Fl L Ar socket-name
.Nm
stores the server socket in a directory under
@@ -155,6 +151,10 @@ If the socket is accidentally removed, the
signal may be sent to the
.Nm
server process to recreate it.
.It Fl l
Behave as a login shell.
This flag currently has no effect and is for compatibility with other shells
when using tmux as a login shell.
.It Fl q
Set the
.Ic quiet
@@ -213,32 +213,110 @@ prefix key,
.Ql C-b
(Ctrl-b) by default, followed by a command key.
.Pp
Some of the default key bindings are:
The default command key bindings are:
.Pp
.Bl -tag -width Ds -offset indent -compact
.Bl -tag -width "XXXXXXXXXX" -offset indent -compact
.It C-b
Send the prefix key (C-b) through to the application.
.It C-o
Rotate the panes in the current window forwards.
.It C-z
Suspend the
.Nm
client.
.It !
Break the current pane out of the window.
.It \&"
Split the current pane into two, top and bottom.
.It #
List all paste buffers.
.It %
Split the current pane into two, left and right.
.It &
Kill the current window.
.It '
Prompt for a window index to select.
.It ,
Rename the current window.
.It -
Delete the most recently copied buffer of text.
.It .
Prompt for an index to move the current window.
.It 0 to 9
Select windows 0 to 9.
.It :
Enter the
.Nm
command prompt.
.It =
Choose which buffer to paste interactively from a list.
.It \&?
List all key bindings.
.It D
Choose a client to detach.
.It \&[
Enter copy mode to copy text or view the history.
.It \&]
Paste the most recently copied buffer of text.
.It c
Create a new window.
.It d
Detach the current client.
.It f
Prompt to search for text in open windows.
.It i
Display some information about the current window.
.It l
Move to the previously selected window.
.It n
Change to the next window.
.It o
Select the next pane in the current window.
.It p
Change to the previous window.
.It &
Kill the current window.
.It ,
Rename the current window.
.It \&?
List all key bindings.
.It q
Briefly display pane indexes.
.It r
Force redraw of the attached client.
.It s
Select a new session for the attached client interactively.
.It t
Show the time.
.It w
Choose the current window interactively.
.It x
Kill the current pane.
.It {
Swap the current pane with the previous pane.
.It }
Swap the current pane with the next pane.
.It ~
Show previous messages from
.Nm ,
if any.
.It Page Up
Enter copy mode and scroll one page up.
.It Up, Down
.It Left, Right
Change to the pane above, below, to the left, or to the right of the current
pane.
.It M-1 to M-5
Arrange panes in one of the five preset layouts: even-horizontal,
even-vertical, main-horizontal, main-vertical, or tiled.
.It M-n
Move to the next window with a bell or activity marker.
.It M-o
Rotate the panes in the current window backwards.
.It M-p
Move to the previous window with a bell or activity marker.
.It C-Up, C-Down
.It C-Left, C-Right
Resize the current pane in steps of one cell.
.It M-Up, M-Down
.It M-Left, M-Right
Resize the current pane in steps of five cells.
.El
.Pp
A complete list may be obtained with the
.Ic list-keys
command (bound to
.Ql \&?
by default).
Key bindings may be changed with the
.Ic bind-key
and
@@ -336,6 +414,11 @@ If neither a colon nor period appears,
first attempts to use the argument as a pane index; if that fails, it is looked
up as for
.Ar target-window .
A
.Ql +
or
.Ql -
indicate the next or previous pane index, respectively.
One of the strings
.Em top ,
.Em bottom ,
@@ -347,6 +430,18 @@ One of the strings
.Em bottom-right
may be used instead of a pane index.
.Pp
The special characters
.Ql +
and
.Ql -
may be followed by an offset, for example:
.Bd -literal -offset indent
select-window -t:+2
.Ed
.Pp
When dealing with a session that doesn't contain sequential window indexes,
they will be correctly skipped.
.Pp
.Ar shell-command
arguments are
.Xr sh 1
@@ -368,7 +463,6 @@ bind-key F1 set-window-option force-width 81
.Pp
Or if using
.Xr sh 1 :
.Pp
.Bd -literal -offset indent
$ tmux bind-key F1 set-window-option force-width 81
.Ed
@@ -396,13 +490,12 @@ new-window ; split-window -d
.Pp
Or from
.Xr sh 1 :
.Pp
.Bd -literal -offset indent
$ tmux kill-window -t :1
$ tmux new-window \\; split-window -d
$ tmux new-window \e; split-window -d
$ tmux new-session -d 'vi /etc/passwd' \\; split-window -d \\; attach
$ tmux new-session -d 'vi /etc/passwd' \e; split-window -d \e; attach
.Ed
.Sh CLIENTS AND SESSIONS
The
@@ -475,17 +568,15 @@ List the syntax of all commands supported by
.It Ic list-sessions
.D1 (alias: Ic ls )
List all sessions managed by the server.
.It Xo Ic lock-client
.Op Fl t Ar target-client
.Xc
.It Ic lock-client Op Fl t Ar target-client
.D1 (alias: Ic lockc )
Lock
.Ar target-client ,
see the
.Ic lock-server
command.
.It Xo Ic lock-session
.Op Fl t Ar target-session
.Xc
.It Ic lock-session Op Fl t Ar target-session
.D1 (alias: Ic locks )
Lock all clients attached to
.Ar target-session .
.It Xo Ic new-session
@@ -583,14 +674,8 @@ A
.Nm
window may be in one of several modes.
The default permits direct access to the terminal attached to the window.
The others are:
.Bl -tag -width Ds
.It Em output mode
This is entered when a command which produces output, such as
.Ic list-keys ,
is executed from a key binding.
.It Em copy mode
This permits a section of a window or its history to be copied to a
The other is copy mode, which permits a section of a window or its
history to be copied to a
.Em paste buffer
for later insertion into another window.
This mode is entered with the
@@ -598,14 +683,16 @@ This mode is entered with the
command, bound to
.Ql \&[
by default.
.El
It is also entered when a command that produces output, such as
.Ic list-keys ,
is executed from a key binding.
.Pp
The keys available depend on whether emacs or vi mode is selected
(see the
.Ic mode-keys
option).
The following keys are supported as appropriate for the mode:
.Bl -column "FunctionXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent
.Bl -column "FunctionXXXXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent
.It Sy "Function" Ta Sy "vi" Ta Sy "emacs"
.It Li "Back to indentation" Ta "^" Ta "M-m"
.It Li "Bottom of history" Ta "G" Ta "M-<"
@@ -624,6 +711,10 @@ The following keys are supported as appropriate for the mode:
.It Li "Go to line" Ta ":" Ta "g"
.It Li "Half page down" Ta "C-d" Ta "M-Down"
.It Li "Half page up" Ta "C-u" Ta "M-Up"
.It Li "Jump forward" Ta "f" Ta "f"
.It Li "Jump backward" Ta "F" Ta "F"
.It Li "Jump again" Ta ";" Ta ";"
.It Li "Jump again in reverse" Ta "," Ta ","
.It Li "Next page" Ta "C-f" Ta "Page down"
.It Li "Next space" Ta "W" Ta ""
.It Li "Next space, end of word" Ta "E" Ta ""
@@ -661,6 +752,18 @@ next word and previous word to the start of the previous word.
The three next and previous space keys work similarly but use a space alone as
the word separator.
.Pp
The jump commands enable quick movement within a line.
For instance, typing
.Ql f
followed by
.Ql /
will move the cursor to the next
.Ql /
character on the current line.
A
.Ql \&;
will then jump to the next occurrence.
.Pp
Commands in copy mode may be prefaced by an optional repeat count.
With vi key bindings, a prefix is entered using the number keys; with
emacs, the Alt (meta) key and a number begins prefix entry.
@@ -680,7 +783,7 @@ and
.Em emacs-choice
for keys used when choosing from lists (such as produced by the
.Ic choose-window
command) or in output mode; and
command); and
.Em vi-copy
and
.Em emacs-copy
@@ -695,7 +798,9 @@ and
The paste buffer key pastes the first line from the top paste buffer on the
stack.
.Pp
The mode commands are as follows:
The synopsis for the
.Ic copy-mode
command is:
.Bl -tag -width Ds
.It Xo Ic copy-mode
.Op Fl u
@@ -727,10 +832,8 @@ command (bound to
and
.Ql C-right
by default), the current pane may be changed with the
.Ic up-pane
and
.Ic down-pane
commands and the
.Ic select-pane
command and the
.Ic rotate-window
and
.Ic swap-pane
@@ -769,8 +872,29 @@ bottom along the right.
See the
.Em main-pane-width
window option.
.It Ic tiled
Panes are spread out as evenly as possible over the window in both rows and
columns.
.El
.Pp
In addition,
.Ic select-layout
may be used to apply a previously used layout - the
.Ic list-windows
command displays the layout of each window in a form suitable for use with
.Ic select-layout .
For example:
.Bd -literal -offset indent
$ tmux list-windows
0: ksh [159x48]
layout: bb62,159x48,0,0{79x48,0,0,79x48,80,0}
$ tmux select-layout bb62,159x48,0,0{79x48,0,0,79x48,80,0}
.Ed
.Nm
automatically adjusts the size of the layout for the current window size.
Note that a layout cannot be applied to a window with more panes than that
from which the layout was originally defined.
.Pp
Commands related to windows and panes are as follows:
.Bl -tag -width Ds
.It Xo Ic break-pane
@@ -859,9 +983,6 @@ While the indicator is on screen, a pane may be selected with the
to
.Ql 9
keys.
.It Ic down-pane Op Fl t Ar target-pane
.D1 (alias: Ic downp )
Change the active pane to the next pane (higher index).
.It Xo Ic find-window
.Op Fl t Ar target-window
.Ar match-string
@@ -948,7 +1069,7 @@ List the panes in the current window or in
List windows in the current session or in
.Ar target-session .
.It Xo Ic move-window
.Op Fl d
.Op Fl dk
.Op Fl s Ar src-window
.Op Fl t Ar dst-window
.Xc
@@ -960,13 +1081,22 @@ except the window at
is moved to
.Ar dst-window .
.It Xo Ic new-window
.Op Fl dk
.Op Fl adk
.Op Fl n Ar window-name
.Op Fl t Ar target-window
.Op Ar shell-command
.Xc
.D1 (alias: Ic neww )
Create a new window.
With
.Fl a ,
the new window is inserted at the next index up from the specified
.Ar target-window ,
moving windows up if necessary,
otherwise
.Ar target-window
is the new window location.
.Pp
If
.Fl d
is given, the session does not make the new window the current window.
@@ -1024,6 +1154,11 @@ A pane may only be piped to one command at a time, any existing pipe is
closed before
.Ar shell-command
is executed.
The
.Ar shell-command
string may contain the special character sequences supported by the
.Ic status-left
command.
If no
.Ar shell-command
is given, the current pipe (if any) is closed.
@@ -1033,8 +1168,13 @@ The
option only opens a new pipe if no previous pipe exists, allowing a pipe to
be toggled with a single key, for example:
.Bd -literal -offset indent
bind-key C-p pipe-pane -o 'cat >>~/output'
bind-key C-p pipe-pane -o 'cat >>~/output.#I-#P'
.Ed
.It Xo Ic previous-layout
.Op Fl t Ar target-window
.Xc
.D1 (alias: Ic prevl )
Move to the previous layout in the session.
.It Xo Ic previous-window
.Op Fl a
.Op Fl t Ar target-session
@@ -1098,17 +1238,28 @@ or downward (numerically higher).
.Op Fl t Ar target-window
.Op Ar layout-name
.Xc
.D1 (alias: selectl )
.D1 (alias: Ic selectl )
Choose a specific layout for a window.
If
.Ar layout-name
is not given, the last layout used (if any) is reapplied.
.It Ic select-pane Op Fl t Ar target-pane
is not given, the last preset layout used (if any) is reapplied.
.It Xo Ic select-pane
.Op Fl DLRU
.Op Fl t Ar target-pane
.Xc
.D1 (alias: Ic selectp )
Make pane
.Ar target-pane
the active pane in window
.Ar target-window .
If one of
.Fl D ,
.Fl L ,
.Fl R ,
or
.Fl U
is used, respectively the pane below, to the left, to the right, or above the
target pane is used.
.It Ic select-window Op Fl t Ar target-window
.D1 (alias: Ic selectw )
Select the window at
@@ -1121,7 +1272,7 @@ Select the window at
.Op Fl t Ar target-pane
.Op Ar shell-command
.Xc
.D1 (alias: splitw )
.D1 (alias: Ic splitw )
Create a new pane by splitting
.Ar target-pane :
.Fl h
@@ -1184,9 +1335,6 @@ if
.Fl k
is specified and the window is linked to only one session, it is unlinked and
destroyed.
.It Ic up-pane Op Fl t Ar target-pane
.D1 (alias: Ic upp )
Change the active pane to the previous pane (lower index).
.El
.Sh KEY BINDINGS
.Nm
@@ -1233,7 +1381,7 @@ or
keys, quotation marks are necessary, for example:
.Bd -literal -offset indent
bind-key '"' split-window
bind-key "'" select-prompt
bind-key "'" new-window
.Ed
.Pp
Commands related to key bindings are as follows:
@@ -1427,6 +1575,11 @@ Available window options are listed under
.Pp
Available server options are:
.Bl -tag -width Ds
.It Ic detach-on-destroy
If on (the default), the client is detached when the session it is attached to
is destroyed.
If off, the client is switched to the most recently active of the remaining
sessions.
.It Ic escape-time
Set the time in milliseconds for which
.Nm
@@ -1491,7 +1644,8 @@ is used as a login shell.
.It Ic default-path Ar path
Set the default working directory for processes created from keys, or
interactively from the prompt.
The default is the current working directory when the server is started.
The default is empty, which means to use the working directory of the shell
from which the server was started if it is available or the user's home if not.
.It Ic default-terminal Ar terminal
Set the default terminal for new windows created in this session - the
default value of the
@@ -1557,7 +1711,7 @@ This has no effect as a session option; it must be set as a global option.
Set status line message attributes, where
.Ar attributes
is either
.Ic default
.Ic none
or a comma-delimited list of one or more of:
.Ic bright
(or
@@ -1712,6 +1866,19 @@ the
.Ic status-interval
option: if the status line is redrawn in the meantime, the previous result is
used.
Shell commands are executed with the
.Nm
global environment set (see the
.Sx ENVIRONMENT
section).
.Pp
The window title (#T) is the title set by the program running within the window
using the OSC title setting sequence, for example:
.Bd -literal -offset indent
$ printf '\e033]2;My Title\e033\e\e'
.Ed
.Pp
When a window is first created, its title is the hostname.
.Pp
#[attributes] allows a comma-separated list of attributes to be specified,
these may be
@@ -1957,10 +2124,8 @@ Key bindings default to emacs.
.Op Ic on | off
.Xc
Mouse state in modes.
If on,
.Nm
will respond to mouse clicks by moving the cursor in copy mode or selecting an
option in choice mode.
If on, the mouse may be used to copy a selection by dragging in copy mode, or
to select an option in choice mode.
.Pp
.It Xo Ic monitor-activity
.Op Ic on | off
@@ -1988,8 +2153,8 @@ command.
.It Xo Ic synchronize-panes
.Op Ic on | off
.Xc
Duplicate input to any pane to all other panes in the same window, except
for panes that are not in output mode.
Duplicate input to any pane to all other panes in the same window (only
for panes that are not in any special mode).
.Pp
.It Xo Ic alternate-screen
.Op Ic on | off
@@ -2028,6 +2193,16 @@ option for details of special character sequences available.
The default is
.Ql #I:#W#F .
.Pp
.It Ic window-status-alert-attr Ar attributes
Set status line attributes for windows which have an alert (bell, activity
or content).
.Pp
.It Ic window-status-alert-bg Ar colour
Set status line background colour for windows with an alert.
.Pp
.It Ic window-status-alert-fg Ar colour
Set status line foreground colour for windows with an alert.
.Pp
.It Ic window-status-current-attr Ar attributes
Set status line attributes for the currently active window.
.Pp
@@ -2271,10 +2446,6 @@ The format of
is as for
.Ic status-left ,
with the exception that #() are not handled.
.It Ic select-prompt Op Fl t Ar target-client
Open a prompt inside
.Ar target-client
allowing a window index to be entered interactively.
.El
.Sh BUFFERS
.Nm
@@ -2302,6 +2473,23 @@ command above).
.Pp
The buffer commands are as follows:
.Bl -tag -width Ds
.It Xo
.Ic choose-buffer
.Op Fl t Ar target-window
.Op Ar template
.Xc
Put a window into buffer choice mode, where a buffer may be chosen
interactively from a list.
After a buffer is selected,
.Ql %%
is replaced by the buffer index in
.Ar template
and the result executed as a command.
If
.Ar template
is not given, "paste-buffer -b '%%'" is used.
This command works only from inside
.Nm .
.It Ic clear-history Op Fl t Ar target-pane
.D1 (alias: Ic clearhist )
Remove and free the history for the specified pane.
@@ -2336,18 +2524,23 @@ Load the contents of the specified paste buffer from
.It Xo Ic paste-buffer
.Op Fl dr
.Op Fl b Ar buffer-index
.Op Fl t Ar target-window
.Op Fl s Ar separator
.Op Fl t Ar target-pane
.Xc
.D1 (alias: Ic pasteb )
Insert the contents of a paste buffer into the current window.
Insert the contents of a paste buffer into the specified pane.
If not specified, paste into the current one.
With
.Fl d ,
also delete the paste buffer from the stack.
When output, any linefeed (LF) characters in the paste buffer are replaced with
carriage returns (CR).
This translation may be disabled with the
.Fl r
a separator, by default carriage return (CR).
A custom separator may be specified using the
.Fl s
flag.
The
.Fl r
flag means to do no replacement (equivalent to a separator of LF).
.It Xo Ic save-buffer
.Op Fl a
.Op Fl b Ar buffer-index
@@ -2398,7 +2591,7 @@ option.
Execute
.Ar shell-command
in the background without creating a window.
After it finishes, any output to stdout is displayed in output mode.
After it finishes, any output to stdout is displayed in copy mode.
If the command doesn't return success, the exit status is also displayed.
.It Ic server-info
.D1 (alias: Ic info )

128
tmux.c
View File

@@ -1,4 +1,4 @@
/* $Id: tmux.c,v 1.204 2010-02-26 13:31:39 tcunha Exp $ */
/* $Id: tmux.c,v 1.214 2010-07-17 14:36:41 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#include <event.h>
@@ -40,6 +41,8 @@ struct options global_s_options; /* session options */
struct options global_w_options; /* window options */
struct environ global_environ;
struct event_base *ev_base;
int debug_level;
time_t start_time;
char *socket_path;
@@ -57,11 +60,7 @@ char *makesockpath(const char *);
__dead void shell_exec(const char *, const char *);
struct imsgbuf *main_ibuf;
struct event main_ev_sigterm;
int main_exitval;
void main_set_signals(void);
void main_clear_signals(void);
void main_signal(int, short, unused void *);
void main_callback(int, short, void *);
void main_dispatch(const char *);
@@ -242,7 +241,7 @@ main(int argc, char **argv)
struct env_data envdata;
struct msg_command_data cmddata;
char *s, *shellcmd, *path, *label, *home, *cause;
char cwd[MAXPATHLEN], **var;
char **var;
void *buf;
size_t len;
int opt, flags, quiet = 0, cmdflags = 0;
@@ -342,10 +341,12 @@ main(int argc, char **argv)
options_set_number(so, "bell-action", BELL_ANY);
options_set_number(so, "buffer-limit", 9);
options_set_string(so, "default-command", "%s", "");
options_set_string(so, "default-path", "%s", "");
options_set_string(so, "default-shell", "%s", getshell());
options_set_string(so, "default-terminal", "screen");
options_set_number(so, "display-panes-colour", 4);
options_set_number(so, "detach-on-destroy", 1);
options_set_number(so, "display-panes-active-colour", 1);
options_set_number(so, "display-panes-colour", 4);
options_set_number(so, "display-panes-time", 1000);
options_set_number(so, "display-time", 750);
options_set_number(so, "history-limit", 2000);
@@ -357,8 +358,8 @@ main(int argc, char **argv)
options_set_number(so, "message-fg", 0);
options_set_number(so, "message-limit", 20);
options_set_number(so, "mouse-select-pane", 0);
options_set_number(so, "pane-active-border-bg", 2);
options_set_number(so, "pane-active-border-fg", 8);
options_set_number(so, "pane-active-border-bg", 8);
options_set_number(so, "pane-active-border-fg", 2);
options_set_number(so, "pane-border-bg", 8);
options_set_number(so, "pane-border-fg", 8);
options_set_number(so, "repeat-time", 500);
@@ -419,6 +420,9 @@ main(int argc, char **argv)
options_set_number(wo, "window-status-current-bg", 8);
options_set_number(wo, "window-status-current-fg", 8);
options_set_number(wo, "window-status-fg", 8);
options_set_number(wo, "window-status-alert-attr", GRID_ATTR_REVERSE);
options_set_number(wo, "window-status-alert-bg", 8);
options_set_number(wo, "window-status-alert-fg", 8);
options_set_string(wo, "window-status-format", "#I:#W#F");
options_set_string(wo, "window-status-current-format", "#I:#W#F");
options_set_string(wo, "word-separators", " -_@");
@@ -434,15 +438,6 @@ main(int argc, char **argv)
options_set_number(wo, "utf8", 0);
}
if (getcwd(cwd, sizeof cwd) == NULL) {
pw = getpwuid(getuid());
if (pw->pw_dir != NULL && *pw->pw_dir != '\0')
strlcpy(cwd, pw->pw_dir, sizeof cwd);
else
strlcpy(cwd, "/", sizeof cwd);
}
options_set_string(so, "default-path", "%s", cwd);
if (cfg_file == NULL) {
home = getenv("HOME");
if (home == NULL || *home == '\0') {
@@ -517,7 +512,7 @@ main(int argc, char **argv)
exit(1);
}
cmdflags &= ~CMD_STARTSERVER;
TAILQ_FOREACH(cmd, cmdlist, qentry) {
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if (cmd->entry->flags & CMD_STARTSERVER)
cmdflags |= CMD_STARTSERVER;
if (cmd->entry->flags & CMD_SENDENVIRON)
@@ -540,10 +535,6 @@ main(int argc, char **argv)
exit(1);
}
if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL)
exit(1);
xfree(path);
#ifdef HAVE_BROKEN_KQUEUE
if (setenv("EVENT_NOKQUEUE", "1", 1) != 0)
fatal("setenv failed");
@@ -552,85 +543,46 @@ main(int argc, char **argv)
if (setenv("EVENT_NOPOLL", "1", 1) != 0)
fatal("setenv failed");
#endif
event_init();
ev_base = event_init();
#ifdef HAVE_BROKEN_KQUEUE
unsetenv("EVENT_NOKQUEUE");
#endif
#ifdef HAVE_BROKEN_POLL
unsetenv("EVENT_NOPOLL");
#endif
set_signals(main_signal);
/* Initialise the client socket/start the server. */
if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL)
exit(1);
xfree(path);
imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len);
main_set_signals();
events = EV_READ;
if (main_ibuf->w.queued > 0)
events |= EV_WRITE;
event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL);
main_exitval = 0;
event_dispatch();
main_clear_signals();
clear_signals();
client_main(); /* doesn't return */
}
void
main_set_signals(void)
{
struct sigaction sigact;
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
signal_set(&main_ev_sigterm, SIGTERM, main_signal, NULL);
signal_add(&main_ev_sigterm, NULL);
}
void
main_clear_signals(void)
{
struct sigaction sigact;
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_DFL;
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
event_del(&main_ev_sigterm);
}
/* ARGSUSED */
void
main_signal(int sig, unused short events, unused void *data)
{
int status;
switch (sig) {
case SIGTERM:
exit(1);
case SIGCHLD:
waitpid(WAIT_ANY, &status, WNOHANG);
break;
}
}
@@ -659,8 +611,8 @@ main_dispatch(const char *shellcmd)
{
struct imsg imsg;
ssize_t n, datalen;
struct msg_print_data printdata;
struct msg_shell_data shelldata;
struct msg_exit_data exitdata;
if ((n = imsg_read(main_ibuf)) == -1 || n == 0)
fatalx("imsg_read failed");
@@ -675,21 +627,13 @@ main_dispatch(const char *shellcmd)
switch (imsg.hdr.type) {
case MSG_EXIT:
case MSG_SHUTDOWN:
if (datalen != 0)
fatalx("bad MSG_EXIT size");
exit(main_exitval);
case MSG_ERROR:
case MSG_PRINT:
if (datalen != sizeof printdata)
fatalx("bad MSG_PRINT size");
memcpy(&printdata, imsg.data, sizeof printdata);
printdata.msg[(sizeof printdata.msg) - 1] = '\0';
log_info("%s", printdata.msg);
if (imsg.hdr.type == MSG_ERROR)
main_exitval = 1;
break;
if (datalen != sizeof exitdata) {
if (datalen != 0)
fatalx("bad MSG_EXIT size");
exit(0);
}
memcpy(&exitdata, imsg.data, sizeof exitdata);
exit(exitdata.retcode);
case MSG_READY:
if (datalen != 0)
fatalx("bad MSG_READY size");
@@ -709,7 +653,7 @@ main_dispatch(const char *shellcmd)
memcpy(&shelldata, imsg.data, sizeof shelldata);
shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
main_clear_signals();
clear_signals();
shell_exec(shelldata.shell, shellcmd);
default:

182
tmux.h
View File

@@ -1,4 +1,4 @@
/* $Id: tmux.h,v 1.547 2010-03-08 15:02:07 tcunha Exp $ */
/* $Id: tmux.h,v 1.571 2010-07-17 14:38:13 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -21,7 +21,7 @@
#include "config.h"
#define PROTOCOL_VERSION 5
#define PROTOCOL_VERSION 6
#include <sys/param.h>
#include <sys/time.h>
@@ -67,7 +67,6 @@ extern char **environ;
*/
#define COMMAND_LENGTH 2048 /* packed argv size */
#define TERMINAL_LENGTH 128 /* length of TERM environment variable */
#define PRINT_LENGTH 512 /* printed error/message size */
#define ENVIRON_LENGTH 1024 /* environment variable length */
/*
@@ -110,6 +109,10 @@ extern char **environ;
#define KEYC_SHIFT 0x8000
#define KEYC_PREFIX 0x10000
/* Mask to obtain key w/o modifiers */
#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_PREFIX)
#define KEYC_MASK_KEY (~KEYC_MASK_MOD)
/* Other key codes. */
enum key_code {
/* Mouse key. */
@@ -368,7 +371,9 @@ enum msgtype {
MSG_ENVIRON,
MSG_UNLOCK,
MSG_LOCK,
MSG_SHELL
MSG_SHELL,
MSG_STDERR,
MSG_STDOUT,
};
/*
@@ -376,10 +381,6 @@ enum msgtype {
*
* Don't forget to bump PROTOCOL_VERSION if any of these change!
*/
struct msg_print_data {
char msg[PRINT_LENGTH];
};
struct msg_command_data {
pid_t pid; /* pid from $TMUX or -1 */
u_int idx; /* index from $TMUX */
@@ -411,6 +412,10 @@ struct msg_shell_data {
char shell[MAXPATHLEN];
};
struct msg_exit_data {
int retcode;
};
/* Mode key commands. */
enum mode_key_cmd {
MODEKEY_NONE,
@@ -458,6 +463,10 @@ enum mode_key_cmd {
MODEKEYCOPY_HALFPAGEUP,
MODEKEYCOPY_HISTORYBOTTOM,
MODEKEYCOPY_HISTORYTOP,
MODEKEYCOPY_JUMP,
MODEKEYCOPY_JUMPAGAIN,
MODEKEYCOPY_JUMPREVERSE,
MODEKEYCOPY_JUMPBACK,
MODEKEYCOPY_LEFT,
MODEKEYCOPY_MIDDLELINE,
MODEKEYCOPY_NEXTPAGE,
@@ -536,6 +545,8 @@ struct mode_key_table {
#define MODE_KCURSOR 0x4
#define MODE_KKEYPAD 0x8 /* set = application, clear = number */
#define MODE_MOUSE 0x10
#define MODE_MOUSEMOTION 0x20
#define MODE_WRAP 0x40 /* whether lines wrap */
/*
* A single UTF-8 character.
@@ -718,59 +729,52 @@ struct screen_write_ctx {
#define screen_hsize(s) ((s)->grid->hsize)
#define screen_hlimit(s) ((s)->grid->hlimit)
/* Input parser sequence argument. */
struct input_arg {
u_char data[64];
size_t used;
};
/* Input parser context. */
struct input_ctx {
struct window_pane *wp;
struct window_pane *wp;
struct screen_write_ctx ctx;
u_char *buf;
size_t len;
size_t off;
size_t was;
struct grid_cell cell;
struct grid_cell cell;
struct grid_cell old_cell;
u_int old_cx;
u_int old_cy;
struct grid_cell saved_cell;
u_int saved_cx;
u_int saved_cy;
u_char interm_buf[4];
size_t interm_len;
#define MAXSTRINGLEN 1024
u_char *string_buf;
size_t string_len;
int string_type;
#define STRING_SYSTEM 0
#define STRING_APPLICATION 1
#define STRING_NAME 2
u_char param_buf[64];
size_t param_len;
struct utf8_data utf8data;
u_char input_buf[256];
size_t input_len;
u_char intermediate;
void *(*state)(u_char, struct input_ctx *);
int param_list[24]; /* -1 not present */
u_int param_list_len;
u_char private;
ARRAY_DECL(, struct input_arg) args;
struct utf8_data utf8data;
int ch;
int flags;
#define INPUT_DISCARD 0x1
const struct input_state *state;
};
/*
* Window mode. Windows can be in several modes and this is used to call the
* right function to handle input and output.
*/
struct client;
struct session;
struct window;
struct mouse_event;
struct window_mode {
struct screen *(*init)(struct window_pane *);
void (*free)(struct window_pane *);
void (*resize)(struct window_pane *, u_int, u_int);
void (*key)(struct window_pane *, struct client *, int);
void (*key)(struct window_pane *, struct session *, int);
void (*mouse)(struct window_pane *,
struct client *, struct mouse_event *);
struct session *, struct mouse_event *);
void (*timer)(struct window_pane *);
};
@@ -839,8 +843,7 @@ struct window {
#define WINDOW_BELL 0x1
#define WINDOW_HIDDEN 0x2
#define WINDOW_ACTIVITY 0x4
#define WINDOW_CONTENT 0x8
#define WINDOW_REDRAW 0x10
#define WINDOW_REDRAW 0x8
struct options options;
@@ -857,6 +860,12 @@ struct winlink {
struct grid_cell status_cell;
char *status_text;
int flags;
#define WINLINK_BELL 0x1
#define WINLINK_ACTIVITY 0x2
#define WINLINK_CONTENT 0x4
#define WINLINK_ALERTFLAGS (WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_CONTENT)
RB_ENTRY(winlink) entry;
TAILQ_ENTRY(winlink) sentry;
};
@@ -908,13 +917,6 @@ struct environ_entry {
RB_HEAD(environ, environ_entry);
/* Client session. */
struct session_alert {
struct winlink *wl;
int type;
SLIST_ENTRY(session_alert) entry;
};
struct session_group {
TAILQ_HEAD(, session) sessions;
@@ -924,6 +926,7 @@ TAILQ_HEAD(session_groups, session_group);
struct session {
char *name;
char *cwd;
struct timeval creation_time;
struct timeval activity_time;
@@ -939,8 +942,6 @@ struct session {
struct paste_stack buffers;
SLIST_HEAD(, session_alert) alerts;
#define SESSION_UNATTACHED 0x1 /* not attached to any clients */
#define SESSION_DEAD 0x2
int flags;
@@ -1052,9 +1053,23 @@ struct tty_ctx {
u_int last_width;
};
/*
* xterm mouse mode is fairly silly. Buttons are in the bottom two
* bits: 0 button 1; 1 button 2; 2 button 3; 3 buttons released.
*
* Bit 3 is shift; bit 4 is meta; bit 5 control.
*
* Bit 6 is added for mouse buttons 4 and 5.
*/
/* Mouse input. */
struct mouse_event {
u_char b;
#define MOUSE_1 0
#define MOUSE_2 1
#define MOUSE_3 2
#define MOUSE_UP 3
#define MOUSE_BUTTON 3
#define MOUSE_45 64
u_char x;
u_char y;
};
@@ -1069,6 +1084,7 @@ struct message_entry {
struct client {
struct imsgbuf ibuf;
struct event event;
int retcode;
struct timeval creation_time;
struct timeval activity_time;
@@ -1079,6 +1095,10 @@ struct client {
char *cwd;
struct tty tty;
FILE *stdin_file;
FILE *stdout_file;
FILE *stderr_file;
struct event repeat_timer;
struct timeval status_timer;
@@ -1087,7 +1107,7 @@ struct client {
#define CLIENT_TERMINAL 0x1
#define CLIENT_PREFIX 0x2
#define CLIENT_MOUSE 0x4
/* 0x4 unused */
#define CLIENT_REDRAW 0x8
#define CLIENT_STATUS 0x10
#define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */
@@ -1161,7 +1181,10 @@ struct cmd {
TAILQ_ENTRY(cmd) qentry;
};
TAILQ_HEAD(cmd_list, cmd);
struct cmd_list {
int references;
TAILQ_HEAD(, cmd) list;
};
struct cmd_entry {
const char *name;
@@ -1254,6 +1277,7 @@ extern struct options global_options;
extern struct options global_s_options;
extern struct options global_w_options;
extern struct environ global_environ;
extern struct event_base *ev_base;
extern char *cfg_file;
extern int debug_level;
extern int be_quiet;
@@ -1332,6 +1356,7 @@ void environ_set(struct environ *, const char *, const char *);
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 *);
/* tty.c */
void tty_raw(struct tty *, const char *);
@@ -1349,7 +1374,7 @@ void tty_puts(struct tty *, const char *);
void tty_putc(struct tty *, u_char);
void tty_pututf8(struct tty *, const struct grid_utf8 *);
void tty_init(struct tty *, int, char *);
void tty_resize(struct tty *);
int tty_resize(struct tty *);
void tty_start_tty(struct tty *);
void tty_stop_tty(struct tty *);
void tty_set_title(struct tty *, const char *);
@@ -1404,6 +1429,7 @@ int paste_free_top(struct paste_stack *);
int paste_free_index(struct paste_stack *, u_int);
void paste_add(struct paste_stack *, char *, size_t, u_int);
int paste_replace(struct paste_stack *, u_int, char *, size_t);
char *paste_print(struct paste_buffer *, size_t);
/* clock.c */
extern const char clock_table[14][5][5];
@@ -1440,6 +1466,7 @@ extern const struct cmd_entry cmd_attach_session_entry;
extern const struct cmd_entry cmd_bind_key_entry;
extern const struct cmd_entry cmd_break_pane_entry;
extern const struct cmd_entry cmd_capture_pane_entry;
extern const struct cmd_entry cmd_choose_buffer_entry;
extern const struct cmd_entry cmd_choose_client_entry;
extern const struct cmd_entry cmd_choose_session_entry;
extern const struct cmd_entry cmd_choose_window_entry;
@@ -1494,7 +1521,6 @@ extern const struct cmd_entry cmd_run_shell_entry;
extern const struct cmd_entry cmd_save_buffer_entry;
extern const struct cmd_entry cmd_select_layout_entry;
extern const struct cmd_entry cmd_select_pane_entry;
extern const struct cmd_entry cmd_select_prompt_entry;
extern const struct cmd_entry cmd_select_window_entry;
extern const struct cmd_entry cmd_send_keys_entry;
extern const struct cmd_entry cmd_send_prefix_entry;
@@ -1583,8 +1609,6 @@ const char *key_string_lookup_key(int);
extern struct clients clients;
extern struct clients dead_clients;
int server_start(char *);
void server_signal_set(void);
void server_signal_clear(void);
void server_update_socket(void);
/* server-client.c */
@@ -1599,7 +1623,6 @@ void server_window_loop(void);
/* server-fn.c */
void server_fill_environ(struct session *, struct environ *);
void server_write_error(struct client *, const char *);
void server_write_client(
struct client *, enum msgtype, const void *, size_t);
void server_write_session(
@@ -1801,6 +1824,10 @@ struct winlink *winlink_add(struct winlinks *, struct window *, int);
void winlink_remove(struct winlinks *, struct winlink *);
struct winlink *winlink_next(struct winlink *);
struct winlink *winlink_previous(struct winlink *);
struct winlink *winlink_next_by_number(struct winlink *, struct session *,
int);
struct winlink *winlink_previous_by_number(struct winlink *, struct session *,
int);
void winlink_stack_push(struct winlink_stack *, struct winlink *);
void winlink_stack_remove(struct winlink_stack *, struct winlink *);
int window_index(struct window *, u_int *);
@@ -1815,6 +1842,10 @@ struct window_pane *window_add_pane(struct window *, u_int);
void window_resize(struct window *, u_int, u_int);
void window_remove_pane(struct window *, struct window_pane *);
struct window_pane *window_pane_at_index(struct window *, u_int);
struct window_pane *window_pane_next_by_number(struct window *,
struct window_pane *, u_int);
struct window_pane *window_pane_previous_by_number(struct window *,
struct window_pane *, u_int);
u_int window_pane_index(struct window *, struct window_pane *);
u_int window_count_panes(struct window *);
void window_destroy_panes(struct window *);
@@ -1824,21 +1855,30 @@ int window_pane_spawn(struct window_pane *, const char *,
const char *, const char *, struct environ *,
struct termios *, char **);
void window_pane_resize(struct window_pane *, u_int, u_int);
void window_pane_alternate_on(
struct window_pane *, struct grid_cell *);
void window_pane_alternate_off(
struct window_pane *, struct grid_cell *);
int window_pane_set_mode(
struct window_pane *, const struct window_mode *);
void window_pane_reset_mode(struct window_pane *);
void window_pane_parse(struct window_pane *);
void window_pane_key(struct window_pane *, struct client *, int);
void window_pane_key(struct window_pane *, struct session *, int);
void window_pane_mouse(struct window_pane *,
struct client *, struct mouse_event *);
struct session *, struct mouse_event *);
int window_pane_visible(struct window_pane *);
char *window_pane_search(
struct window_pane *, const char *, u_int *);
struct window_pane *window_pane_find_up(struct window_pane *);
struct window_pane *window_pane_find_down(struct window_pane *);
struct window_pane *window_pane_find_left(struct window_pane *);
struct window_pane *window_pane_find_right(struct window_pane *);
/* layout.c */
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 *, struct layout_cell **);
void layout_set_size(
struct layout_cell *, u_int, u_int, u_int, u_int);
void layout_make_leaf(
@@ -1859,6 +1899,10 @@ struct layout_cell *layout_split_pane(
struct window_pane *, enum layout_type, int);
void layout_close_pane(struct window_pane *);
/* layout-custom.c */
char *layout_dump(struct window *);
int layout_parse(struct window *, const char *);
/* layout-set.c */
const char *layout_set_name(u_int);
int layout_set_lookup(const char *);
@@ -1869,19 +1913,19 @@ void layout_set_active_changed(struct window *);
/* layout-string.c */
struct layout_cell *layout_find_string(struct window *, const char *);
struct layout_cell *layout_find_bottomright(struct layout_cell *);
/* window-clock.c */
extern const struct window_mode window_clock_mode;
/* window-copy.c */
extern const struct window_mode window_copy_mode;
void window_copy_init_from_pane(struct window_pane *);
void window_copy_init_for_output(struct window_pane *);
void 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 *);
/* window-more.c */
extern const struct window_mode window_more_mode;
void window_more_add(struct window_pane *, const char *, ...);
void window_more_vadd(struct window_pane *, const char *, va_list);
/* window-choose.c */
extern const struct window_mode window_choose_mode;
void window_choose_vadd(
@@ -1895,14 +1939,14 @@ void window_choose_ready(struct window_pane *,
void queue_window_name(struct window *);
char *default_window_name(struct window *);
/* signal.c */
void set_signals(void(*handler)(int, short, unused void *));
void clear_signals(void);
/* session.c */
extern struct sessions sessions;
extern struct sessions dead_sessions;
extern struct session_groups session_groups;
void session_alert_add(struct session *, struct window *, int);
void session_alert_cancel(struct session *, struct winlink *);
int session_alert_has(struct session *, struct winlink *, int);
int session_alert_has_window(struct session *, struct window *, int);
struct session *session_find(const char *);
struct session *session_create(const char *, const char *, const char *,
struct environ *, struct termios *, int, u_int, u_int,
@@ -1914,7 +1958,7 @@ struct winlink *session_new(struct session *,
struct winlink *session_attach(
struct session *, struct window *, int, char **);
int session_detach(struct session *, struct winlink *);
int session_has(struct session *, struct window *);
struct winlink* session_has(struct session *, struct window *);
int session_next(struct session *, int);
int session_previous(struct session *, int);
int session_select(struct session *, int);

View File

@@ -1,6 +1,6 @@
# $Id: dist.mk,v 1.8 2010-03-10 15:16:19 tcunha Exp $
# $Id: dist.mk,v 1.9 2010-07-18 13:36:52 tcunha Exp $
VERSION= 1.2
VERSION= 1.3
DISTDIR= tmux-${VERSION}
DISTFILES= *.[ch] Makefile GNUmakefile configure tmux.1 \

View File

@@ -1,4 +1,4 @@
/* $Id: tty-keys.c,v 1.55 2009-12-18 18:57:00 tcunha Exp $ */
/* $Id: tty-keys.c,v 1.57 2010-06-06 00:23:44 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -408,7 +408,7 @@ tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size)
(*size)++;
/* At the end of the string, return the current node. */
if (len == 0)
if (len == 0 || (tk->next == NULL && tk->key != KEYC_NONE))
return (tk);
/* Move into the next tree for the following character. */
@@ -612,7 +612,8 @@ tty_keys_mouse(const char *buf, size_t len, size_t *size, struct mouse_event *m)
return (1);
*size = 6;
log_debug("mouse input is: %.6s", buf);
log_debug(
"mouse input: %.6s (%hhu,%hhu/%hhu)", buf, buf[4], buf[5], buf[3]);
m->b = buf[3];
m->x = buf[4];

60
tty.c
View File

@@ -1,4 +1,4 @@
/* $Id: tty.c,v 1.189 2010-03-08 14:53:49 tcunha Exp $ */
/* $Id: tty.c,v 1.192 2010-06-06 00:30:34 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -73,34 +73,55 @@ tty_init(struct tty *tty, int fd, char *term)
tty->term_flags = 0;
}
void
int
tty_resize(struct tty *tty)
{
struct winsize ws;
u_int sx, sy;
if (ioctl(tty->fd, TIOCGWINSZ, &ws) != -1) {
tty->sx = ws.ws_col;
tty->sy = ws.ws_row;
sx = ws.ws_col;
if (sx == 0)
sx = 80;
sy = ws.ws_row;
if (sy == 0)
sy = 24;
} else {
sx = 80;
sy = 24;
}
if (tty->sx == 0)
tty->sx = 80;
if (tty->sy == 0)
tty->sy = 24;
if (sx == tty->sx && sy == tty->sy)
return (0);
tty->sx = sx;
tty->sy = sy;
tty->cx = UINT_MAX;
tty->cy = UINT_MAX;
tty->rupper = UINT_MAX;
tty->rlower = UINT_MAX;
/*
* If the terminal has been started, reset the actual scroll region and
* cursor position, as this may not have happened.
*/
if (tty->flags & TTY_STARTED) {
tty_cursor(tty, 0, 0);
tty_region(tty, 0, tty->sy - 1);
}
return (1);
}
int
tty_open(struct tty *tty, const char *overrides, char **cause)
{
char out[64];
int fd;
if (debug_level > 3) {
fd = open("tmux.out", O_WRONLY|O_CREAT|O_TRUNC, 0644);
xsnprintf(out, sizeof out, "tmux-out-%ld.log", (long) getpid());
fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
tty->log_fd = fd;
@@ -402,11 +423,18 @@ tty_update_mode(struct tty *tty, int mode)
else
tty_putcode(tty, TTYC_CIVIS);
}
if (changed & MODE_MOUSE) {
if (mode & MODE_MOUSE)
tty_puts(tty, "\033[?1000h");
else
tty_puts(tty, "\033[?1000l");
if (changed & (MODE_MOUSE|MODE_MOUSEMOTION)) {
if (mode & MODE_MOUSE) {
if (mode & MODE_MOUSEMOTION)
tty_puts(tty, "\033[?1003h");
else
tty_puts(tty, "\033[?1000h");
} else {
if (mode & MODE_MOUSEMOTION)
tty_puts(tty, "\033[?1003l");
else
tty_puts(tty, "\033[?1000l");
}
}
if (changed & MODE_KKEYPAD) {
if (mode & MODE_KKEYPAD)
@@ -1083,7 +1111,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy)
* Use HPA if change is larger than absolute, otherwise move
* the cursor with CUB/CUF.
*/
if (abs(change) > cx && tty_term_has(term, TTYC_HPA)) {
if ((u_int) abs(change) > cx && tty_term_has(term, TTYC_HPA)) {
tty_putcode1(tty, TTYC_HPA, cx);
goto out;
} else if (change > 0 && tty_term_has(term, TTYC_CUB)) {
@@ -1119,7 +1147,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy)
* Try to use VPA if change is larger than absolute or if this
* change would cross the scroll region, otherwise use CUU/CUD.
*/
if (abs(change) > cy ||
if ((u_int) abs(change) > cy ||
(change < 0 && cy - change > tty->rlower) ||
(change > 0 && cy - change < tty->rupper)) {
if (tty_term_has(term, TTYC_VPA)) {

View File

@@ -1,4 +1,4 @@
/* $Id: window-choose.c,v 1.29 2010-02-02 23:55:21 tcunha Exp $ */
/* $Id: window-choose.c,v 1.30 2010-05-22 21:56:04 micahcowan Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -25,9 +25,9 @@
struct screen *window_choose_init(struct window_pane *);
void window_choose_free(struct window_pane *);
void window_choose_resize(struct window_pane *, u_int, u_int);
void window_choose_key(struct window_pane *, struct client *, int);
void window_choose_key(struct window_pane *, struct session *, int);
void window_choose_mouse(
struct window_pane *, struct client *, struct mouse_event *);
struct window_pane *, struct session *, struct mouse_event *);
void window_choose_redraw_screen(struct window_pane *);
void window_choose_write_line(
@@ -171,7 +171,7 @@ window_choose_resize(struct window_pane *wp, u_int sx, u_int sy)
/* ARGSUSED */
void
window_choose_key(struct window_pane *wp, unused struct client *c, int key)
window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
{
struct window_choose_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
@@ -304,7 +304,7 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key)
/* ARGSUSED */
void
window_choose_mouse(
struct window_pane *wp, unused struct client *c, struct mouse_event *m)
struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
{
struct window_choose_mode_data *data = wp->modedata;
struct screen *s = &data->screen;

View File

@@ -1,4 +1,4 @@
/* $Id: window-clock.c,v 1.11 2009-12-04 22:14:47 tcunha Exp $ */
/* $Id: window-clock.c,v 1.12 2010-05-22 21:56:04 micahcowan Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,7 +26,7 @@
struct screen *window_clock_init(struct window_pane *);
void window_clock_free(struct window_pane *);
void window_clock_resize(struct window_pane *, u_int, u_int);
void window_clock_key(struct window_pane *, struct client *, int);
void window_clock_key(struct window_pane *, struct session *, int);
void window_clock_timer(struct window_pane *);
void window_clock_draw_screen(struct window_pane *);
@@ -85,7 +85,7 @@ window_clock_resize(struct window_pane *wp, u_int sx, u_int sy)
/* ARGSUSED */
void
window_clock_key(
struct window_pane *wp, unused struct client *c, unused int key)
struct window_pane *wp, unused struct session *sess, unused int key)
{
window_pane_reset_mode(wp);
}

View File

@@ -1,4 +1,4 @@
/* $Id: window-copy.c,v 1.109 2010-03-08 15:02:07 tcunha Exp $ */
/* $Id: window-copy.c,v 1.121 2010-07-02 02:56:07 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,11 +26,11 @@
struct screen *window_copy_init(struct window_pane *);
void window_copy_free(struct window_pane *);
void window_copy_resize(struct window_pane *, u_int, u_int);
void window_copy_key(struct window_pane *, struct client *, int);
void window_copy_key(struct window_pane *, struct session *, int);
int window_copy_key_input(struct window_pane *, int);
int window_copy_key_numeric_prefix(struct window_pane *, int);
void window_copy_mouse(
struct window_pane *, struct client *, struct mouse_event *);
struct window_pane *, struct session *, struct mouse_event *);
void window_copy_redraw_lines(struct window_pane *, u_int, u_int);
void window_copy_redraw_screen(struct window_pane *);
@@ -52,7 +52,7 @@ 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 *);
int window_copy_update_selection(struct window_pane *);
void window_copy_copy_selection(struct window_pane *, struct client *);
void window_copy_copy_selection(struct window_pane *, struct session *);
void window_copy_clear_selection(struct window_pane *);
void window_copy_copy_line(
struct window_pane *, char **, size_t *, u_int, u_int, u_int);
@@ -65,6 +65,8 @@ void window_copy_cursor_left(struct window_pane *);
void window_copy_cursor_right(struct window_pane *);
void window_copy_cursor_up(struct window_pane *, int);
void window_copy_cursor_down(struct window_pane *, int);
void window_copy_cursor_jump(struct window_pane *);
void window_copy_cursor_jump_back(struct window_pane *);
void window_copy_cursor_next_word(struct window_pane *, const char *);
void window_copy_cursor_next_word_end(struct window_pane *, const char *);
void window_copy_cursor_previous_word(struct window_pane *, const char *);
@@ -86,12 +88,33 @@ enum window_copy_input_type {
WINDOW_COPY_NUMERICPREFIX,
WINDOW_COPY_SEARCHUP,
WINDOW_COPY_SEARCHDOWN,
WINDOW_COPY_JUMPFORWARD,
WINDOW_COPY_JUMPBACK,
WINDOW_COPY_GOTOLINE,
};
/*
* Copy-mode's visible screen (the "screen" field) is filled from one of
* two sources: the original contents of the pane (used when we
* actually enter via the "copy-mode" command, to copy the contents of
* the current pane), or else a series of lines containing the output
* from an output-writing tmux command (such as any of the "show-*" or
* "list-*" commands).
*
* In either case, the full content of the copy-mode grid is pointed at
* by the "backing" field, and is copied into "screen" as needed (that
* is, when scrolling occurs). When copy-mode is backed by a pane,
* backing points directly at that pane's screen structure (&wp->base);
* when backed by a list of output-lines from a command, it points at
* a newly-allocated screen structure (which is deallocated when the
* mode ends).
*/
struct window_copy_mode_data {
struct screen screen;
struct screen *backing;
int backing_written; /* backing display has started */
struct mode_key_data mdata;
u_int oy;
@@ -115,6 +138,9 @@ struct window_copy_mode_data {
enum window_copy_input_type searchtype;
char *searchstr;
enum window_copy_input_type jumptype;
char jumpchar;
};
struct screen *
@@ -122,18 +148,18 @@ window_copy_init(struct window_pane *wp)
{
struct window_copy_mode_data *data;
struct screen *s;
struct screen_write_ctx ctx;
u_int i;
int keys;
wp->modedata = data = xmalloc(sizeof *data);
data->oy = 0;
data->cx = wp->base.cx;
data->cy = wp->base.cy;
data->cx = 0;
data->cy = 0;
data->lastcx = 0;
data->lastsx = 0;
data->backing_written = 0;
data->rectflag = 0;
data->inputtype = WINDOW_COPY_OFF;
@@ -147,6 +173,9 @@ window_copy_init(struct window_pane *wp)
wp->flags |= PANE_FREEZE;
bufferevent_disable(wp->event, EV_READ|EV_WRITE);
data->jumptype = WINDOW_COPY_OFF;
data->jumpchar = '\0';
s = &data->screen;
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
if (options_get_number(&wp->window->options, "mode-mouse"))
@@ -158,6 +187,26 @@ window_copy_init(struct window_pane *wp)
else
mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
data->backing = NULL;
return (s);
}
void
window_copy_init_from_pane(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
u_int i;
if (wp->mode != &window_copy_mode)
fatalx("not in copy mode");
data->backing = &wp->base;
data->cx = data->backing->cx;
data->cy = data->backing->cy;
s->cx = data->cx;
s->cy = data->cy;
@@ -166,8 +215,17 @@ window_copy_init(struct window_pane *wp)
window_copy_write_line(wp, &ctx, i);
screen_write_cursormove(&ctx, data->cx, data->cy);
screen_write_stop(&ctx);
}
return (s);
void
window_copy_init_for_output(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
data->backing = xmalloc(sizeof *data->backing);
screen_init(data->backing, screen_size_x(&wp->base),
screen_size_y(&wp->base), UINT_MAX);
data->backing->mode &= ~MODE_WRAP;
}
void
@@ -182,11 +240,73 @@ window_copy_free(struct window_pane *wp)
xfree(data->searchstr);
xfree(data->inputstr);
if (data->backing != &wp->base) {
screen_free(data->backing);
xfree(data->backing);
}
screen_free(&data->screen);
xfree(data);
}
void
window_copy_add(struct window_pane *wp, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
window_copy_vadd(wp, fmt, ap);
va_end(ap);
}
void
window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *backing = data->backing;
struct screen_write_ctx back_ctx, ctx;
struct grid_cell gc;
int utf8flag;
u_int old_hsize;
if (backing == &wp->base)
return;
utf8flag = options_get_number(&wp->window->options, "utf8");
memcpy(&gc, &grid_default_cell, sizeof gc);
old_hsize = screen_hsize(data->backing);
screen_write_start(&back_ctx, NULL, backing);
if (data->backing_written) {
/*
* On the second or later line, do a CRLF before writing
* (so it's on a new line).
*/
screen_write_carriagereturn(&back_ctx);
screen_write_linefeed(&back_ctx, 0);
} else
data->backing_written = 1;
screen_write_vnputs(&back_ctx, 0, &gc, utf8flag, fmt, ap);
screen_write_stop(&back_ctx);
data->oy += screen_hsize(data->backing) - old_hsize;
screen_write_start(&ctx, wp, &data->screen);
/*
* If the history has changed, draw the top line.
* (If there's any history at all, it has changed.)
*/
if (screen_hsize(data->backing))
window_copy_redraw_lines(wp, 0, 1);
/* Write the line, if it's visible. */
if (backing->cy + data->oy < screen_size_y(backing))
window_copy_redraw_lines(wp, backing->cy, 1);
screen_write_stop(&ctx);
}
void
window_copy_pageup(struct window_pane *wp)
{
@@ -197,8 +317,8 @@ window_copy_pageup(struct window_pane *wp)
n = 1;
if (screen_size_y(s) > 2)
n = screen_size_y(s) - 2;
if (data->oy + n > screen_hsize(&wp->base))
data->oy = screen_hsize(&wp->base);
if (data->oy + n > screen_hsize(data->backing))
data->oy = screen_hsize(data->backing);
else
data->oy += n;
window_copy_update_selection(wp);
@@ -213,6 +333,8 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
struct screen_write_ctx ctx;
screen_resize(s, sx, sy);
if (data->backing != &wp->base)
screen_resize(data->backing, sx, sy);
if (data->cy > sy - 1)
data->cy = sy - 1;
@@ -229,7 +351,7 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
}
void
window_copy_key(struct window_pane *wp, struct client *c, int key)
window_copy_key(struct window_pane *wp, struct session *sess, int key)
{
const char *word_separators;
struct window_copy_mode_data *data = wp->modedata;
@@ -242,7 +364,24 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
if (np == 0)
np = 1;
if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
if (data->inputtype == WINDOW_COPY_JUMPFORWARD
|| data->inputtype == WINDOW_COPY_JUMPBACK) {
/* Ignore keys with modifiers. */
if ((key & KEYC_MASK_MOD) == 0) {
data->jumpchar = key;
if (data->inputtype == WINDOW_COPY_JUMPFORWARD) {
for (; np != 0; np--)
window_copy_cursor_jump(wp);
} else {
for (; np != 0; np--)
window_copy_cursor_jump_back(wp);
}
}
data->jumptype = data->inputtype;
data->inputtype = WINDOW_COPY_OFF;
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
return;
} if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
if (window_copy_key_numeric_prefix(wp, key) == 0)
return;
data->inputtype = WINDOW_COPY_OFF;
@@ -256,9 +395,8 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
cmd = mode_key_lookup(&data->mdata, key);
switch (cmd) {
case MODEKEYCOPY_CANCEL:
for (; np != 0; np--)
window_pane_reset_mode(wp);
break;
window_pane_reset_mode(wp);
return;
case MODEKEYCOPY_LEFT:
for (; np != 0; np--)
window_copy_cursor_left(wp);
@@ -303,8 +441,8 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
case MODEKEYCOPY_HALFPAGEUP:
n = screen_size_y(s) / 2;
for (; np != 0; np--) {
if (data->oy + n > screen_hsize(&wp->base))
data->oy = screen_hsize(&wp->base);
if (data->oy + n > screen_hsize(data->backing))
data->oy = screen_hsize(data->backing);
else
data->oy += n;
}
@@ -343,7 +481,7 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
case MODEKEYCOPY_HISTORYTOP:
data->cx = 0;
data->cy = 0;
data->oy = screen_hsize(&wp->base);
data->oy = screen_hsize(data->backing);
window_copy_update_selection(wp);
window_copy_redraw_screen(wp);
break;
@@ -363,9 +501,10 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
window_copy_redraw_screen(wp);
break;
case MODEKEYCOPY_COPYSELECTION:
if (c != NULL && c->session != NULL) {
window_copy_copy_selection(wp, c);
if (sess != NULL) {
window_copy_copy_selection(wp, sess);
window_pane_reset_mode(wp);
return;
}
break;
case MODEKEYCOPY_STARTOFLINE:
@@ -407,6 +546,36 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
for (; np != 0; np--)
window_copy_cursor_previous_word(wp, word_separators);
break;
case MODEKEYCOPY_JUMP:
data->inputtype = WINDOW_COPY_JUMPFORWARD;
data->inputprompt = "Jump Forward";
*data->inputstr = '\0';
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
return; /* skip numprefix reset */
case MODEKEYCOPY_JUMPAGAIN:
if (data->jumptype == WINDOW_COPY_JUMPFORWARD) {
for (; np != 0; np--)
window_copy_cursor_jump(wp);
} else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
for (; np != 0; np--)
window_copy_cursor_jump_back(wp);
}
break;
case MODEKEYCOPY_JUMPREVERSE:
if (data->jumptype == WINDOW_COPY_JUMPFORWARD) {
for (; np != 0; np--)
window_copy_cursor_jump_back(wp);
} else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
for (; np != 0; np--)
window_copy_cursor_jump(wp);
}
break;
case MODEKEYCOPY_JUMPBACK:
data->inputtype = WINDOW_COPY_JUMPBACK;
data->inputprompt = "Jump Back";
*data->inputstr = '\0';
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
return; /* skip numprefix reset */
case MODEKEYCOPY_SEARCHUP:
data->inputtype = WINDOW_COPY_SEARCHUP;
data->inputprompt = "Search Up";
@@ -420,6 +589,8 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
switch (data->searchtype) {
case WINDOW_COPY_OFF:
case WINDOW_COPY_GOTOLINE:
case WINDOW_COPY_JUMPFORWARD:
case WINDOW_COPY_JUMPBACK:
case WINDOW_COPY_NUMERICPREFIX:
break;
case WINDOW_COPY_SEARCHUP:
@@ -456,7 +627,7 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
*data->inputstr = '\0';
goto input_on;
case MODEKEYCOPY_STARTNUMBERPREFIX:
key &= 0xff;
key &= KEYC_MASK_KEY;
if (key >= '0' && key <= '9') {
data->inputtype = WINDOW_COPY_NUMERICPREFIX;
data->numprefix = 0;
@@ -524,6 +695,8 @@ window_copy_key_input(struct window_pane *wp, int key)
switch (data->inputtype) {
case WINDOW_COPY_OFF:
case WINDOW_COPY_JUMPFORWARD:
case WINDOW_COPY_JUMPBACK:
case WINDOW_COPY_NUMERICPREFIX:
break;
case WINDOW_COPY_SEARCHUP:
@@ -568,7 +741,7 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key)
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
key &= 0xff;
key &= KEYC_MASK_KEY;
if (key < '0' || key > '9')
return 1;
@@ -583,29 +756,63 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key)
/* ARGSUSED */
void
window_copy_mouse(
struct window_pane *wp, unused struct client *c, struct mouse_event *m)
struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
u_int i;
if ((m->b & 3) == 3)
return;
if (m->x >= screen_size_x(s))
return;
if (m->y >= screen_size_y(s))
return;
window_copy_update_cursor(wp, m->x, m->y);
if (window_copy_update_selection(wp))
/* If mouse wheel (buttons 4 and 5), scroll. */
if ((m->b & MOUSE_45)) {
if ((m->b & MOUSE_BUTTON) == MOUSE_1) {
for (i = 0; i < 5; i++)
window_copy_cursor_up(wp, 0);
} else if ((m->b & MOUSE_BUTTON) == MOUSE_2) {
for (i = 0; i < 5; i++)
window_copy_cursor_down(wp, 0);
}
return;
}
/*
* If already reading motion, move the cursor while buttons are still
* pressed, or stop the selection on their release.
*/
if (s->mode & MODE_MOUSEMOTION) {
if ((m->b & MOUSE_BUTTON) != MOUSE_UP) {
window_copy_update_cursor(wp, m->x, m->y);
if (window_copy_update_selection(wp))
window_copy_redraw_screen(wp);
} else {
s->mode &= ~MODE_MOUSEMOTION;
if (sess != NULL) {
window_copy_copy_selection(wp, sess);
window_pane_reset_mode(wp);
}
}
return;
}
/* Otherwise i other buttons pressed, start selection and motion. */
if ((m->b & MOUSE_BUTTON) != MOUSE_UP) {
s->mode |= MODE_MOUSEMOTION;
window_copy_update_cursor(wp, m->x, m->y);
window_copy_start_selection(wp);
window_copy_redraw_screen(wp);
}
}
void
window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &wp->base;
struct grid *gd = s->grid;
struct grid *gd = data->backing->grid;
u_int offset, gap;
data->cx = px;
@@ -700,7 +907,7 @@ void
window_copy_search_up(struct window_pane *wp, const char *searchstr)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &wp->base, ss;
struct screen *s = data->backing, ss;
struct screen_write_ctx ctx;
struct grid *gd = s->grid, *sgd;
struct grid_cell gc;
@@ -757,7 +964,7 @@ void
window_copy_search_down(struct window_pane *wp, const char *searchstr)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &wp->base, ss;
struct screen *s = data->backing, ss;
struct screen_write_ctx ctx;
struct grid *gd = s->grid, *sgd;
struct grid_cell gc;
@@ -817,7 +1024,7 @@ window_copy_goto_line(struct window_pane *wp, const char *linestr)
const char *errstr;
u_int lineno;
lineno = strtonum(linestr, 0, screen_hsize(&wp->base), &errstr);
lineno = strtonum(linestr, 0, screen_hsize(data->backing), &errstr);
if (errstr != NULL)
return;
@@ -845,7 +1052,7 @@ window_copy_write_line(
last = screen_size_y(s) - 1;
if (py == 0) {
size = xsnprintf(hdr, sizeof hdr,
"[%u/%u]", data->oy, screen_hsize(&wp->base));
"[%u/%u]", data->oy, screen_hsize(data->backing));
screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
screen_write_puts(ctx, &gc, "%s", hdr);
} else if (py == last && data->inputtype != WINDOW_COPY_OFF) {
@@ -862,8 +1069,9 @@ window_copy_write_line(
size = 0;
screen_write_cursormove(ctx, xoff, py);
screen_write_copy(ctx, &wp->base, xoff, (screen_hsize(&wp->base) -
data->oy) + py, screen_size_x(s) - size, 1);
screen_write_copy(ctx, data->backing, xoff,
(screen_hsize(data->backing) - data->oy) + py,
screen_size_x(s) - size, 1);
if (py == data->cy && data->cx == screen_size_x(s)) {
memcpy(&gc, &grid_default_cell, sizeof gc);
@@ -932,7 +1140,7 @@ window_copy_start_selection(struct window_pane *wp)
struct screen *s = &data->screen;
data->selx = data->cx;
data->sely = screen_hsize(&wp->base) + data->cy - data->oy;
data->sely = screen_hsize(data->backing) + data->cy - data->oy;
s->sel.flag = 1;
window_copy_update_selection(wp);
@@ -957,7 +1165,7 @@ window_copy_update_selection(struct window_pane *wp)
gc.attr |= options_get_number(oo, "mode-attr");
/* Find top of screen. */
ty = screen_hsize(&wp->base) - data->oy;
ty = screen_hsize(data->backing) - data->oy;
/* Adjust the selection. */
sx = data->selx;
@@ -994,7 +1202,7 @@ window_copy_update_selection(struct window_pane *wp)
}
void
window_copy_copy_selection(struct window_pane *wp, struct client *c)
window_copy_copy_selection(struct window_pane *wp, struct session *sess)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
@@ -1018,7 +1226,7 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c)
/* Find start and end. */
xx = data->cx;
yy = screen_hsize(&wp->base) + data->cy - data->oy;
yy = screen_hsize(data->backing) + data->cy - data->oy;
if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
sx = xx; sy = yy;
ex = data->selx; ey = data->sely;
@@ -1089,20 +1297,21 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c)
off--; /* remove final \n */
/* Add the buffer to the stack. */
limit = options_get_number(&c->session->options, "buffer-limit");
paste_add(&c->session->buffers, buf, off, limit);
limit = options_get_number(&sess->options, "buffer-limit");
paste_add(&sess->buffers, buf, off, limit);
}
void
window_copy_copy_line(struct window_pane *wp,
char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
{
struct grid *gd = wp->base.grid;
const struct grid_cell *gc;
const struct grid_utf8 *gu;
struct grid_line *gl;
u_int i, xx, wrapped = 0;
size_t size;
struct window_copy_mode_data *data = wp->modedata;
struct grid *gd = data->backing->grid;
const struct grid_cell *gc;
const struct grid_utf8 *gu;
struct grid_line *gl;
u_int i, xx, wrapped = 0;
size_t size;
if (sx > ex)
return;
@@ -1157,7 +1366,7 @@ window_copy_clear_selection(struct window_pane *wp)
screen_clear_selection(&data->screen);
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if (data->cx > px)
window_copy_update_cursor(wp, px, data->cy);
@@ -1166,9 +1375,10 @@ window_copy_clear_selection(struct window_pane *wp)
int
window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
{
const struct grid_cell *gc;
struct window_copy_mode_data *data = wp->modedata;
const struct grid_cell *gc;
gc = grid_peek_cell(wp->base.grid, px, py);
gc = grid_peek_cell(data->backing->grid, px, py);
if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8))
return (0);
if (gc->data == 0x00 || gc->data == 0x7f)
@@ -1179,8 +1389,10 @@ window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
u_int
window_copy_find_length(struct window_pane *wp, u_int py)
{
const struct grid_cell *gc;
u_int px;
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = data->backing;
const struct grid_cell *gc;
u_int px;
/*
* If the pane has been resized, its grid can contain old overlong
@@ -1188,11 +1400,11 @@ window_copy_find_length(struct window_pane *wp, u_int py)
* width of the grid, and screen_write_copy treats them as spaces, so
* ignore them here too.
*/
px = wp->base.grid->linedata[py].cellsize;
if (px > screen_size_x(&wp->base))
px = screen_size_x(&wp->base);
px = s->grid->linedata[py].cellsize;
if (px > screen_size_x(s))
px = screen_size_x(s);
while (px > 0) {
gc = grid_peek_cell(wp->base.grid, px - 1, py);
gc = grid_peek_cell(s->grid, px - 1, py);
if (gc->flags & GRID_FLAG_UTF8)
break;
if (gc->data != ' ')
@@ -1206,7 +1418,17 @@ void
window_copy_cursor_start_of_line(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing;
struct grid *gd = back_s->grid;
u_int py;
if (data->cx == 0) {
py = screen_hsize(back_s) + data->cy - data->oy;
while (py > 0 && gd->linedata[py-1].flags & GRID_LINE_WRAPPED) {
window_copy_cursor_up(wp, 0);
py = screen_hsize(back_s) + data->cy - data->oy;
}
}
window_copy_update_cursor(wp, 0, data->cy);
if (window_copy_update_selection(wp))
window_copy_redraw_lines(wp, data->cy, 1);
@@ -1220,11 +1442,11 @@ window_copy_cursor_back_to_indentation(struct window_pane *wp)
const struct grid_cell *gc;
px = 0;
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
while (px < xx) {
gc = grid_peek_cell(wp->base.grid, px, py);
gc = grid_peek_cell(data->backing->grid, px, py);
if (gc->flags & GRID_FLAG_UTF8)
break;
if (gc->data != ' ')
@@ -1241,21 +1463,22 @@ void
window_copy_cursor_end_of_line(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *base_s = &wp->base;
struct grid *gd = base_s->grid;
struct screen *back_s = data->backing;
struct grid *gd = back_s->grid;
u_int px, py;
py = screen_hsize(base_s) + data->cy - data->oy;
py = screen_hsize(back_s) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if (data->cx == px) {
if (data->screen.sel.flag && data->rectflag)
px = screen_size_x(&wp->base);
px = screen_size_x(back_s);
if (gd->linedata[py].flags & GRID_LINE_WRAPPED) {
while (py < gd->sy + gd->hsize &&
gd->linedata[py].flags & GRID_LINE_WRAPPED) {
window_copy_cursor_down(wp, 0);
py = screen_hsize(base_s) + data->cy - data->oy;
py = screen_hsize(back_s)
+ data->cy - data->oy;
}
px = window_copy_find_length(wp, py);
}
@@ -1290,7 +1513,7 @@ window_copy_cursor_right(struct window_pane *wp)
if (data->screen.sel.flag && data->rectflag)
px = screen_size_x(&data->screen);
else {
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
}
@@ -1311,7 +1534,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
struct screen *s = &data->screen;
u_int ox, oy, px, py;
oy = screen_hsize(&wp->base) + data->cy - data->oy;
oy = screen_hsize(data->backing) + data->cy - data->oy;
ox = window_copy_find_length(wp, oy);
if (ox != 0) {
data->lastcx = data->cx;
@@ -1338,7 +1561,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
}
if (!data->screen.sel.flag || !data->rectflag) {
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if ((data->cx >= data->lastsx && data->cx != px) ||
data->cx > px)
@@ -1353,7 +1576,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
struct screen *s = &data->screen;
u_int ox, oy, px, py;
oy = screen_hsize(&wp->base) + data->cy - data->oy;
oy = screen_hsize(data->backing) + data->cy - data->oy;
ox = window_copy_find_length(wp, oy);
if (ox != 0) {
data->lastcx = data->cx;
@@ -1372,7 +1595,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
}
if (!data->screen.sel.flag || !data->rectflag) {
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if ((data->cx >= data->lastsx && data->cx != px) ||
data->cx > px)
@@ -1380,18 +1603,74 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
}
}
void
window_copy_cursor_jump(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing;
const struct grid_cell *gc;
uint px, py, xx;
px = data->cx + 1;
py = screen_hsize(back_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
while (px < xx) {
gc = grid_peek_cell(back_s->grid, px, py);
if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
&& gc->data == data->jumpchar) {
window_copy_update_cursor(wp, px, data->cy);
if (window_copy_update_selection(wp))
window_copy_redraw_lines(wp, data->cy, 1);
return;
}
px++;
}
}
void
window_copy_cursor_jump_back(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing;
const struct grid_cell *gc;
uint px, py;
px = data->cx;
py = screen_hsize(back_s) + data->cy - data->oy;
if (px > 0)
px--;
for (;;) {
gc = grid_peek_cell(back_s->grid, px, py);
if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
&& gc->data == data->jumpchar) {
window_copy_update_cursor(wp, px, data->cy);
if (window_copy_update_selection(wp))
window_copy_redraw_lines(wp, data->cy, 1);
return;
}
if (px == 0)
break;
px--;
}
}
void
window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *base_s = &wp->base;
struct screen *back_s = data->backing;
u_int px, py, xx, yy;
int expected = 0;
px = data->cx;
py = screen_hsize(base_s) + data->cy - data->oy;
py = screen_hsize(back_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
yy = screen_hsize(base_s) + screen_size_y(base_s) - 1;
yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
/*
* First skip past any nonword characters and then any word characters.
@@ -1409,7 +1688,7 @@ window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
window_copy_cursor_down(wp, 0);
px = 0;
py = screen_hsize(base_s) + data->cy - data->oy;
py = screen_hsize(back_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
} else
px++;
@@ -1426,14 +1705,14 @@ void
window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *base_s = &wp->base;
struct screen *back_s = data->backing;
u_int px, py, xx, yy;
int expected = 1;
px = data->cx;
py = screen_hsize(base_s) + data->cy - data->oy;
py = screen_hsize(back_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
yy = screen_hsize(base_s) + screen_size_y(base_s) - 1;
yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
/*
* First skip past any word characters, then any nonword characters.
@@ -1451,7 +1730,7 @@ window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators)
window_copy_cursor_down(wp, 0);
px = 0;
py = screen_hsize(base_s) + data->cy - data->oy;
py = screen_hsize(back_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
} else
px++;
@@ -1472,7 +1751,7 @@ window_copy_cursor_previous_word(struct window_pane *wp, const char *separators)
u_int px, py;
px = data->cx;
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
/* Move back to the previous word character. */
for (;;) {
@@ -1482,12 +1761,12 @@ window_copy_cursor_previous_word(struct window_pane *wp, const char *separators)
break;
} else {
if (data->cy == 0 &&
(screen_hsize(&wp->base) == 0 ||
data->oy >= screen_hsize(&wp->base) - 1))
(screen_hsize(data->backing) == 0 ||
data->oy >= screen_hsize(data->backing) - 1))
goto out;
window_copy_cursor_up(wp, 0);
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
}
}
@@ -1540,11 +1819,11 @@ window_copy_scroll_down(struct window_pane *wp, u_int ny)
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
if (ny > screen_hsize(&wp->base))
if (ny > screen_hsize(data->backing))
return;
if (data->oy > screen_hsize(&wp->base) - ny)
ny = screen_hsize(&wp->base) - data->oy;
if (data->oy > screen_hsize(data->backing) - ny)
ny = screen_hsize(data->backing) - data->oy;
if (ny == 0)
return;
data->oy += ny;
@@ -1571,7 +1850,7 @@ window_copy_rectangle_toggle(struct window_pane *wp)
data->rectflag = !data->rectflag;
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if (data->cx > px)
window_copy_update_cursor(wp, px, data->cy);

View File

@@ -1,260 +0,0 @@
/* $Id: window-more.c,v 1.42 2010-02-08 18:10:07 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* 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"
struct screen *window_more_init(struct window_pane *);
void window_more_free(struct window_pane *);
void window_more_resize(struct window_pane *, u_int, u_int);
void window_more_key(struct window_pane *, struct client *, int);
void window_more_redraw_screen(struct window_pane *);
void window_more_write_line(
struct window_pane *, struct screen_write_ctx *, u_int);
void window_more_scroll_up(struct window_pane *);
void window_more_scroll_down(struct window_pane *);
const struct window_mode window_more_mode = {
window_more_init,
window_more_free,
window_more_resize,
window_more_key,
NULL,
NULL,
};
struct window_more_mode_data {
struct screen screen;
struct mode_key_data mdata;
ARRAY_DECL(, char *) list;
u_int top;
};
void
window_more_add(struct window_pane *wp, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
window_more_vadd(wp, fmt, ap);
va_end(ap);
}
void
window_more_vadd(struct window_pane *wp, const char *fmt, va_list ap)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
char *msg;
u_int size;
xvasprintf(&msg, fmt, ap);
ARRAY_ADD(&data->list, msg);
screen_write_start(&ctx, wp, NULL);
size = ARRAY_LENGTH(&data->list) - 1;
if (size >= data->top && size <= data->top + screen_size_y(s) - 1) {
window_more_write_line(wp, &ctx, size - data->top);
if (size != data->top)
window_more_write_line(wp, &ctx, 0);
} else
window_more_write_line(wp, &ctx, 0);
screen_write_stop(&ctx);
}
struct screen *
window_more_init(struct window_pane *wp)
{
struct window_more_mode_data *data;
struct screen *s;
int keys;
wp->modedata = data = xmalloc(sizeof *data);
ARRAY_INIT(&data->list);
data->top = 0;
s = &data->screen;
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
s->mode &= ~MODE_CURSOR;
keys = options_get_number(&wp->window->options, "mode-keys");
if (keys == MODEKEY_EMACS)
mode_key_init(&data->mdata, &mode_key_tree_emacs_choice);
else
mode_key_init(&data->mdata, &mode_key_tree_vi_choice);
return (s);
}
void
window_more_free(struct window_pane *wp)
{
struct window_more_mode_data *data = wp->modedata;
u_int i;
for (i = 0; i < ARRAY_LENGTH(&data->list); i++)
xfree(ARRAY_ITEM(&data->list, i));
ARRAY_FREE(&data->list);
screen_free(&data->screen);
xfree(data);
}
void
window_more_resize(struct window_pane *wp, u_int sx, u_int sy)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
screen_resize(s, sx, sy);
window_more_redraw_screen(wp);
}
/* ARGSUSED */
void
window_more_key(struct window_pane *wp, unused struct client *c, int key)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
switch (mode_key_lookup(&data->mdata, key)) {
case MODEKEYCHOICE_CANCEL:
window_pane_reset_mode(wp);
break;
case MODEKEYCHOICE_UP:
case MODEKEYCHOICE_SCROLLUP:
window_more_scroll_up(wp);
break;
case MODEKEYCHOICE_DOWN:
case MODEKEYCHOICE_SCROLLDOWN:
window_more_scroll_down(wp);
break;
case MODEKEYCHOICE_PAGEUP:
if (data->top < screen_size_y(s))
data->top = 0;
else
data->top -= screen_size_y(s);
window_more_redraw_screen(wp);
break;
case MODEKEYCHOICE_PAGEDOWN:
if (data->top + screen_size_y(s) > ARRAY_LENGTH(&data->list))
data->top = ARRAY_LENGTH(&data->list);
else
data->top += screen_size_y(s);
window_more_redraw_screen(wp);
break;
default:
break;
}
}
void
window_more_write_line(
struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct options *oo = &wp->window->options;
struct grid_cell gc;
char *msg, hdr[32];
size_t size;
int utf8flag;
utf8flag = options_get_number(&wp->window->options, "utf8");
memcpy(&gc, &grid_default_cell, sizeof gc);
if (py == 0) {
size = xsnprintf(hdr, sizeof hdr,
"[%u/%u]", data->top, ARRAY_LENGTH(&data->list));
screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
colour_set_fg(&gc, options_get_number(oo, "mode-fg"));
colour_set_bg(&gc, options_get_number(oo, "mode-bg"));
gc.attr |= options_get_number(oo, "mode-attr");
screen_write_puts(ctx, &gc, "%s", hdr);
memcpy(&gc, &grid_default_cell, sizeof gc);
} else
size = 0;
screen_write_cursormove(ctx, 0, py);
if (data->top + py < ARRAY_LENGTH(&data->list)) {
msg = ARRAY_ITEM(&data->list, data->top + py);
screen_write_nputs(
ctx, screen_size_x(s) - size, &gc, utf8flag, "%s", msg);
}
while (s->cx < screen_size_x(s) - size)
screen_write_putc(ctx, &gc, ' ');
}
void
window_more_redraw_screen(struct window_pane *wp)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
u_int i;
screen_write_start(&ctx, wp, NULL);
for (i = 0; i < screen_size_y(s); i++)
window_more_write_line(wp, &ctx, i);
screen_write_stop(&ctx);
}
void
window_more_scroll_up(struct window_pane *wp)
{
struct window_more_mode_data *data = wp->modedata;
struct screen_write_ctx ctx;
if (data->top == 0)
return;
data->top--;
screen_write_start(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0);
screen_write_insertline(&ctx, 1);
window_more_write_line(wp, &ctx, 0);
window_more_write_line(wp, &ctx, 1);
screen_write_stop(&ctx);
}
void
window_more_scroll_down(struct window_pane *wp)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
if (data->top >= ARRAY_LENGTH(&data->list))
return;
data->top++;
screen_write_start(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0);
screen_write_deleteline(&ctx, 1);
window_more_write_line(wp, &ctx, screen_size_y(s) - 1);
window_more_write_line(wp, &ctx, 0);
screen_write_stop(&ctx);
}

301
window.c
View File

@@ -1,4 +1,4 @@
/* $Id: window.c,v 1.126 2010-02-08 18:10:07 tcunha Exp $ */
/* $Id: window.c,v 1.134 2010-07-17 14:38:13 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -170,6 +170,28 @@ winlink_previous(struct winlink *wl)
return (RB_PREV(winlinks, wwl, wl));
}
struct winlink *
winlink_next_by_number(struct winlink *wl, struct session *s, int n)
{
for (; n > 0; n--) {
if ((wl = RB_NEXT(winlinks, wwl, wl)) == NULL)
wl = RB_MIN(winlinks, &s->windows);
}
return (wl);
}
struct winlink *
winlink_previous_by_number(struct winlink *wl, struct session *s, int n)
{
for (; n > 0; n--) {
if ((wl = RB_PREV(winlinks, wwl, wl)) == NULL)
wl = RB_MAX(winlinks, &s->windows);
}
return (wl);
}
void
winlink_stack_push(struct winlink_stack *stack, struct winlink *wl)
{
@@ -367,6 +389,29 @@ window_pane_at_index(struct window *w, u_int idx)
return (NULL);
}
struct window_pane *
window_pane_next_by_number(struct window *w, struct window_pane *wp, u_int n)
{
for (; n > 0; n--) {
if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
wp = TAILQ_FIRST(&w->panes);
}
return (wp);
}
struct window_pane *
window_pane_previous_by_number(struct window *w, struct window_pane *wp,
u_int n)
{
for (; n > 0; n--) {
if ((wp = TAILQ_PREV(wp, window_panes, entry)) == NULL)
wp = TAILQ_LAST(&w->panes, window_panes);
}
return (wp);
}
u_int
window_pane_index(struct window *w, struct window_pane *wp)
{
@@ -478,14 +523,11 @@ int
window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
const char *cwd, struct environ *env, struct termios *tio, char **cause)
{
struct winsize ws;
int mode;
char *argv0, **varp, *var;
ARRAY_DECL(, char *) varlist;
struct environ_entry *envent;
const char *ptr;
struct termios tio2;
u_int i;
struct winsize ws;
int mode;
char *argv0;
const char *ptr;
struct termios tio2;
if (wp->fd != -1) {
close(wp->fd);
@@ -528,22 +570,9 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0)
fatal("tcgetattr failed");
ARRAY_INIT(&varlist);
for (varp = environ; *varp != NULL; varp++) {
var = xstrdup(*varp);
var[strcspn(var, "=")] = '\0';
ARRAY_ADD(&varlist, var);
}
for (i = 0; i < ARRAY_LENGTH(&varlist); i++) {
var = ARRAY_ITEM(&varlist, i);
unsetenv(var);
}
RB_FOREACH(envent, environ, env) {
if (envent->value != NULL)
setenv(envent->name, envent->value, 1);
}
environ_push(env);
server_signal_clear();
clear_signals();
log_close();
if (*wp->cmd != '\0') {
@@ -584,9 +613,19 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
void
window_pane_read_callback(unused struct bufferevent *bufev, void *data)
{
struct window_pane *wp = data;
struct window_pane *wp = data;
char *new_data;
size_t new_size;
window_pane_parse(wp);
new_size = EVBUFFER_LENGTH(wp->event->input) - wp->pipe_off;
if (wp->pipe_fd != -1 && new_size > 0) {
new_data = EVBUFFER_DATA(wp->event->input);
bufferevent_write(wp->pipe_event, new_data, new_size);
}
input_parse(wp);
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
}
/* ARGSUSED */
@@ -630,6 +669,81 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
fatal("ioctl failed");
}
/*
* Enter alternative screen mode. A copy of the visible screen is saved and the
* history is not updated
*/
void
window_pane_alternate_on(struct window_pane *wp, struct grid_cell *gc)
{
struct screen *s = &wp->base;
u_int sx, sy;
if (wp->saved_grid != NULL)
return;
if (!options_get_number(&wp->window->options, "alternate-screen"))
return;
sx = screen_size_x(s);
sy = screen_size_y(s);
wp->saved_grid = grid_create(sx, sy, 0);
grid_duplicate_lines(wp->saved_grid, 0, s->grid, screen_hsize(s), sy);
wp->saved_cx = s->cx;
wp->saved_cy = s->cy;
memcpy(&wp->saved_cell, gc, sizeof wp->saved_cell);
grid_view_clear(s->grid, 0, 0, sx, sy);
wp->base.grid->flags &= ~GRID_HISTORY;
wp->flags |= PANE_REDRAW;
}
/* Exit alternate screen mode and restore the copied grid. */
void
window_pane_alternate_off(struct window_pane *wp, struct grid_cell *gc)
{
struct screen *s = &wp->base;
u_int sx, sy;
if (wp->saved_grid == NULL)
return;
if (!options_get_number(&wp->window->options, "alternate-screen"))
return;
sx = screen_size_x(s);
sy = screen_size_y(s);
/*
* If the current size is bigger, temporarily resize to the old size
* before copying back.
*/
if (sy > wp->saved_grid->sy)
screen_resize(s, sx, wp->saved_grid->sy);
/* Restore the grid, cursor position and cell. */
grid_duplicate_lines(s->grid, screen_hsize(s), wp->saved_grid, 0, sy);
s->cx = wp->saved_cx;
if (s->cx > screen_size_x(s) - 1)
s->cx = screen_size_x(s) - 1;
s->cy = wp->saved_cy;
if (s->cy > screen_size_y(s) - 1)
s->cy = screen_size_y(s) - 1;
memcpy(gc, &wp->saved_cell, sizeof *gc);
/*
* Turn history back on (so resize can use it) and then resize back to
* the current size.
*/
wp->base.grid->flags |= GRID_HISTORY;
if (sy > wp->saved_grid->sy)
screen_resize(s, sx, sy);
grid_destroy(wp->saved_grid);
wp->saved_grid = NULL;
wp->flags |= PANE_REDRAW;
}
int
window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode)
{
@@ -659,24 +773,7 @@ window_pane_reset_mode(struct window_pane *wp)
}
void
window_pane_parse(struct window_pane *wp)
{
char *data;
size_t new_size;
new_size = EVBUFFER_LENGTH(wp->event->input) - wp->pipe_off;
if (wp->pipe_fd != -1 && new_size > 0) {
data = EVBUFFER_DATA(wp->event->input);
bufferevent_write(wp->pipe_event, data, new_size);
}
input_parse(wp);
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
}
void
window_pane_key(struct window_pane *wp, struct client *c, int key)
window_pane_key(struct window_pane *wp, struct session *sess, int key)
{
struct window_pane *wp2;
@@ -685,7 +782,7 @@ window_pane_key(struct window_pane *wp, struct client *c, int key)
if (wp->mode != NULL) {
if (wp->mode->key != NULL)
wp->mode->key(wp, c, key);
wp->mode->key(wp, sess, key);
return;
}
@@ -704,7 +801,7 @@ window_pane_key(struct window_pane *wp, struct client *c, int key)
void
window_pane_mouse(
struct window_pane *wp, struct client *c, struct mouse_event *m)
struct window_pane *wp, struct session *sess, struct mouse_event *m)
{
if (!window_pane_visible(wp))
return;
@@ -718,7 +815,7 @@ window_pane_mouse(
if (wp->mode != NULL) {
if (wp->mode->mouse != NULL)
wp->mode->mouse(wp, c, m);
wp->mode->mouse(wp, sess, m);
} else if (wp->fd != -1)
input_mouse(wp, m);
}
@@ -759,3 +856,113 @@ window_pane_search(struct window_pane *wp, const char *searchstr, u_int *lineno)
xfree(newsearchstr);
return (msg);
}
/* Find the pane directly above another. */
struct window_pane *
window_pane_find_up(struct window_pane *wp)
{
struct window_pane *wp2;
u_int left, top;
if (wp == NULL || !window_pane_visible(wp))
return (NULL);
top = wp->yoff;
if (top == 0)
top = wp->window->sy + 1;
left = wp->xoff;
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
if (!window_pane_visible(wp2))
continue;
if (wp2->yoff + wp2->sy + 1 != top)
continue;
if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx)
return (wp2);
}
return (NULL);
}
/* Find the pane directly below another. */
struct window_pane *
window_pane_find_down(struct window_pane *wp)
{
struct window_pane *wp2;
u_int left, bottom;
if (wp == NULL || !window_pane_visible(wp))
return (NULL);
bottom = wp->yoff + wp->sy + 1;
if (bottom >= wp->window->sy)
bottom = 0;
left = wp->xoff;
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
if (!window_pane_visible(wp2))
continue;
if (wp2->yoff != bottom)
continue;
if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx)
return (wp2);
}
return (NULL);
}
/*
* Find the pane directly to the left of another, adjacent to the left side and
* containing the top edge.
*/
struct window_pane *
window_pane_find_left(struct window_pane *wp)
{
struct window_pane *wp2;
u_int left, top;
if (wp == NULL || !window_pane_visible(wp))
return (NULL);
left = wp->xoff;
if (left == 0)
left = wp->window->sx + 1;
top = wp->yoff;
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
if (!window_pane_visible(wp2))
continue;
if (wp2->xoff + wp2->sx + 1 != left)
continue;
if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy)
return (wp2);
}
return (NULL);
}
/*
* Find the pane directly to the right of another, that is adjacent to the
* right edge and including the top edge.
*/
struct window_pane *
window_pane_find_right(struct window_pane *wp)
{
struct window_pane *wp2;
u_int right, top;
if (wp == NULL || !window_pane_visible(wp))
return (NULL);
right = wp->xoff + wp->sx + 1;
if (right >= wp->window->sx)
right = 0;
top = wp->yoff;
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
if (!window_pane_visible(wp2))
continue;
if (wp2->xoff != right)
continue;
if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy)
return (wp2);
}
return (NULL);
}

View File

@@ -63,6 +63,9 @@ development.</li>
system. The portable version is hosted on <a href="http://sf.net/projects/tmux">
SourceForge</a> and runs on Linux, FreeBSD, NetBSD, Solaris and AIX.</p>
<p>tmux depends on <a href="http://www.monkey.org/~provos/libevent/">libevent 1.4</a> and a
terminfo implementation (normally <a href="http://invisible-island.net/ncurses/">ncurses</a>).</p>
<div id="screenshots">
<a href="tmux3.png"><img src="small-tmux3.png" alt="Screenshot"/></a>
<a href="tmux4.png"><img src="small-tmux4.png" alt="Screenshot"/></a>