Skip to content

Commit

Permalink
Reimplemented window size handling
Browse files Browse the repository at this point in the history
this fixes #30
this fixes #17
this fixes #33

 * shellex main executable creates a temporary file
 * perl module writes maximum size to that file
 * preload library reads from there and deletes file
  • Loading branch information
pseyfert committed Jan 3, 2017
1 parent 563d841 commit c14042f
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 34 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright © 2013 Axel Wagner
Copyright © 2016 Axel Wagner and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
3 changes: 2 additions & 1 deletion conf/10-autoexec
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ function shellex_preexec () {

# We write the expanded form of the command to the tempfile, because the
# executet shell will not have our aliases or functions available
echo "rm $file\n$3" > $file
echo "rm $file" > $file
echo "$3" >> $file

# prevent writing meaningless "zsh $file > /dev/null ...." to history
unset HISTFILE
Expand Down
22 changes: 11 additions & 11 deletions doc/autoresize.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ shellex, because when is starting it's output, there is not enough space, for
the tabcompletion, so even if we immediately resize the terminalwindow, it will
be too late and the shell-output is screwed up.

We rectify this, by injecting a custom ioctl-function into urxvt via
LD_PRELOAD, which rewrites all TIOCSWINSZ-requests to have a constant size,
thus faking to the shell that there is more space available, then there
actually is. The actual number of rows is calculated on start of the urxvt and
put into an environment-variable.
We rectify this, by injecting a custom ioctl-function into zsh via LD_PRELOAD,
which rewrites all TIOCGWINSZ-requests to have a constant size. This fakes to
the shell that there is more space available, then there actually is. The
actual number of rows is calculated on start of the urxvt and put into a
temporary file. The size is chosen a bit smaller than the screen, such that if
zsh needs even more space for the tabcompletion than fits on the screen, the
zsh handeling to deal with less space gets active. The filename is generated
with mktemp before either zsh or urxvt start. The file gets unlinked by
preload/main.c once a successful read happened.



With the current state, the window of shellex is able to grow automatically
exactly one time. This is, because zsh is spamming the output with '\n', if we
grow it always and we have yet to figure out why and how to stop that.
Shrinking (i.e. when the tab-completion vanishes again) is not implemented yet.
Shrinking after tab completions mostly works fine: Depending on the
tabcompletion settings, shrinking breaks once one hit the maximum size limit.
54 changes: 37 additions & 17 deletions preload/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

/* We can not take this from <sys/ioctl.h>, because it would define the
* ioctl-function itself
Expand All @@ -22,28 +24,46 @@ int ioctl (int d, int request, char *argp) {
if (orig_ioctl == NULL) {
orig_ioctl = dlsym(RTLD_NEXT, "ioctl");
}

/* We only care for TIOCGWINSZ ioctls */
if (request != 0x5413) {
return orig_ioctl(d, request, argp);
}

static int max_rows = -1;

/* ioctl gets called once before the perl module had the time to determine
* the right size! Leave max_rows negative to indicat that it still needs to
* be read from the SHELLEX_SIZE_FILE */

if (max_rows < 0 ) {
char *str = getenv("SHELLEX_MAX_ROWS");
if (str != NULL) {
max_rows = atoi(str);

char *fname = getenv("SHELLEX_SIZE_FILE");
if (fname != NULL && fname[0] != '\0') {
FILE *stream = fopen(fname,"r");
char str[5] = "-500";
if (stream != NULL) {
char *ret = fgets(str,5,stream);
fclose(stream);
if (ret != NULL) {
/* this may be -500 */
max_rows = atoi(str);
if (max_rows > 0 ) {
unlink(fname);
}
}
}
}
}

// We only care for TIOCSWINSZ ioctls
if (request != 0x5414) {
return orig_ioctl(d, request, argp);
}

struct winsize ws = *((struct winsize *)argp);
int fheight = ws.ws_ypixel / ws.ws_row;
if (max_rows < 0) {
ws.ws_row = 80;
ws.ws_ypixel += 80 * fheight;
} else {
ws.ws_row = max_rows;
ws.ws_ypixel += max_rows * fheight;
}
int retval = orig_ioctl(d, request, (char *)argp);
struct winsize *ws = (struct winsize *)argp;

/* max_rows is still negative at first invocation */
int fheight = ws->ws_ypixel / ws->ws_row;
ws->ws_row = (max_rows > 0) ? max_rows : 25;
ws->ws_ypixel = ws->ws_row * fheight;

return orig_ioctl(d, request, (char *)&ws);
return retval;
}
6 changes: 3 additions & 3 deletions shellex.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
# See shellex(1) for information on invocation.
# © 2013 Axel Wagner and contributors (see also: LICENSE)


export LD_PRELOAD="@PREFIX@@LIBDIR@/shellex/shellex_preload.so"
exec urxvt -perl-lib @PREFIX@@LIBDIR@/shellex/urxvt -pe shellex -override-redirect -name shellex $* -e env -u LD_PRELOAD zsh -f
SHELLEX_PRELOAD="@PREFIX@@LIBDIR@/shellex/shellex_preload.so"
export SHELLEX_SIZE_FILE=$(mktemp -t shellex-size-XXXXXXXX)
exec urxvt -perl-lib @PREFIX@@LIBDIR@/shellex/urxvt -pe shellex -override-redirect -name shellex $* -e env LD_PRELOAD=$SHELLEX_PRELOAD zsh -f
17 changes: 16 additions & 1 deletion urxvt/shellex.in
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,17 @@ sub on_start {

# This environment variable is used by the LD_PRELOAD ioctl-override to
# determine the values to send to the shell
$ENV{SHELLEX_MAX_ROWS} = int($self->{h} / $self->fheight);
# TODO revisit communication protocol (from file to pipe?)
# TODO check if user defined their own SHELLEX_MAX_ROWS, which should be used like
#$ENV{SHELLEX_MAX_ROWS} = $sane_max_rows < $ENV{SHELLEX_MAX_ROWS} ? $sane_max_rows : $ENV{SHELLEX_MAX_ROWS} ;
my $sane_max_rows = int($self->{h} / $self->fheight) - 10;

$ENV{SHELLEX_MAX_ROWS} = $sane_max_rows;
my $filename = $ENV{SHELLEX_SIZE_FILE};
open(my $fh, '>', $filename);
print $fh "$ENV{SHELLEX_MAX_ROWS}\n";
close $fh;
print "writing max rows file done\n";

$self->{border} = $self->x_resource('internalBorder');

Expand All @@ -223,6 +233,8 @@ sub on_start {

my $cfg = gen_conf();

print "loading config\n";
$self->tt_write($self->locale_encode("unset LD_PRELOAD\n"));
$self->tt_write($self->locale_encode(". $cfg\n"));
();
}
Expand All @@ -243,6 +255,7 @@ sub on_line_update {
}
}
$nrow = $nrow > 0 ? $nrow : 1;
$nrow = $nrow > $ENV{SHELLEX_MAX_ROWS} ? $ENV{SHELLEX_MAX_ROWS} : $nrow;
print "resizing to $nrow\n";

# If the window is supposed to be at the bottom, we have to move the
Expand Down Expand Up @@ -315,6 +328,8 @@ sub on_add_lines {
print "add_lines(string = \"$str\")\n";

my $nrow = $self->predict_term_size($string);
$nrow = $nrow > 0 ? $nrow : 1;
$nrow = $nrow > $ENV{SHELLEX_MAX_ROWS} ? $ENV{SHELLEX_MAX_ROWS} : $nrow;
print "resizing to $nrow\n";

# If the window is supposed to be at the bottom, we have to move the
Expand Down

0 comments on commit c14042f

Please sign in to comment.