Commit 95007339 authored by Paul Seyfert's avatar Paul Seyfert

Merge tag 'upstream/0.2'

Upstream version 0.2
parents 6bda8aa1 a725b718
preload/shellex_preload.so
conf/shellexrc
shellex
urxvt/shellex
doc/man/shellex.1
......
Changelog
=========
0.2 - 2016-12-27
----------------
• Added optional sudo configuration
• Bugfix: flashing window with large completion lists
• Moved config handling from perl to shell
• Disable beeping
• Improved history file handling
• Avoid using temporary files for configuration parsing
• Avoid using temporary files for command execution
0.1 - 2013-09-03
----------------
• History support (default)
......
Copyright © 2013 Axel Wagner
Copyright © 2016 Axel Wagner and contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
......@@ -22,3 +22,6 @@ DISCLAIMED. IN NO EVENT SHALL Axel Wagner BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
......@@ -10,6 +10,9 @@ typical launcher-behaviour.
This gives you a simple launcher with tab-completion and other shell-features,
configurable in shell.
See this video for a short demonstration and comparison to another app starter:
![demo](http://virgilio.mib.infn.it/~seyfert/images/shellexdemo.gif)
I tried to do this a few years back, then using C and implementing the
terminal-operations myself. This turned out to be a very bad idea, it made the
design overly complex and the state I left it in had regular segfaults and was far
......@@ -18,7 +21,7 @@ start again, this time using `urxvt` to do the terminal-part, which turned out t
be really easy.
So, this is the early prototype. It is usable and should already work and be
usefull, but much is not working yet. I hope this time I will continue the work
useful, but much is not working yet. I hope this time I will continue the work
for longer ;)
......@@ -47,10 +50,10 @@ Working:
Planned, but not Implemented yet:
* Buffering/showing some output, for errors etc. We have to think about some
magic way to determine, wether output is helpfull or the launcher should be
magic way to determine, wether output is helpful or the launcher should be
hidden immediately
* dmenu-like completion, typing part of a command still completing (maybe zsh
has sometething to do that?)
has something to do that?)
* .desktop-file integration
* Your ticket here
......@@ -62,6 +65,7 @@ There are packages in
* [debian](http://packages.debian.org/search?keywords=shellex&searchon=names&suite=all&section=all&sourceid=mozilla-search)
* Arch Linux: [Arch User Repository](https://aur.archlinux.org/packages/?SeB=n&K=shellex) ([latest Release](https://aur.archlinux.org/packages/shellex/) and [git-Repository](https://aur.archlinux.org/packages/shellex-git/))
* Gentoo: there is an [Overlay](https://github.com/proxypoke/gentoo-overlay) which contains shellex
If you are on one of these distributions, we encourage you to install `shellex`
via your package manager.
......@@ -69,12 +73,46 @@ via your package manager.
Else, or if you want to help developing, just do
```sh
$ git checkout git://github.com/Merovius/shellex.git
$ git clone git://github.com/Merovius/shellex.git
$ cd shellex
$ make
$ make install
```
for installing in `$(HOME).local`
```sh
$ git clone git://github.com/Merovius/shellex.git
$ cd shellex
$ PREFIX=$HOME/.local make
$ PREFIX=$HOME/.local make install
```
Usage
=====
After installing `shellex` you probably want to bind it to a shortcut - most
likely Alt+F2. How to do this depends on your desktop environment and/or window
manager.
## xbindkeys
If you're running [xbindkeys](http://www.nongnu.org/xbindkeys/xbindkeys.html),
the entry for your `~/.xbindkeysrc` file might look like:
```
"shellex"
alt + c:68
```
## i3
[i3](i3wm.org) shortcuts can be modified as described in the
[official documentation](https://i3wm.org/docs/userguide.html).
```
bindsym Mod1+F2 exec shellex
```
Contributing
============
......@@ -97,25 +135,31 @@ following is a not comprehensive list of highly appreciated ways to contribute:
5. Contribute comments and documentation. Consider translating the manpage.
Again, please announce your intention and again, if you translate to a
language, that none of the core-developers speak (currently everything but
english and german) please consider it to be at least a mid-term commitment
English and German) please consider it to be at least a mid-term commitment
to maintain the translation.
Configuration
=============
Configuration of `shellex` has two parts: The first one are X-resources (which
we will try to eliminate in the future):
Configuration of `shellex` has two parts: The first one are X-resources.
Additionally to the urxvt-class, instances run by shellex will also look for
the shellex-class. This makes it possible to customize the appearance of
shellex without interfering with your usual terminals.
There are also two additional resources defined by shellex:
Resource | Values | Default | Description
----------------- | -------------- | ------- | ---
URxvt.shellex.pos | pointer|focus | focus | If pointer, shellex shows the window on the window, the mousepointer is on, else it uses the output, where most of the currently focused window is (falling back to the pointer-method, if the root-window is focused).
URxvt.shellex.edge | bottom|top | top | On what screenedge to show shellex
The other are small shell-script-snippets. When starting, `shellex` will look
into `$HOME/.shellex` and into `/etc/shellex`. It will then source all the
snippets in either location. If there is an identically named file in both
directories, the one in your home will be preferred.
Resource | Values | Default | Description
----------- | -------------- | ------- | ---
shellex.pos | pointer|focus | focus | If pointer, shellex shows the window on the window, the mousepointer is on, else it uses the output, where most of the currently focused window is (falling back to the pointer-method, if the root-window is focused).
shellex.edge | bottom|top | top | On what screenedge to show shellex
The other source of configuration are small shell-script-snippets. When
starting, `shellex` will look into `$HOME/.shellex` and into `/etc/shellex`. It
will then source all the snippets in either location. If there is an
identically named file in both directories, the one in your home will be
preferred.
This makes for a pretty flexible configuration process: Usually there will be a
lot of snippets in `/usr/lib/shellex/conf`, which should be self-contained and
......@@ -128,13 +172,14 @@ just put them in `$HOME/.shellex` under a name not used yet and it will be
automatically sourced.
Changing Appearence
===================
Command-line
============
All command-line parameters given to `shellex` are passed directly to `urxvt`,
so if you want to change colors or font, you can do it through the appropriate
`urxvt`-parameters. For example, to get a dark grey background with a slightly
yellow font you might start shellex with
`urxvt`-parameters (or by using resources, for persistent configuration). For
example, to get a dark grey background with a slightly yellow font you might
start shellex with
```sh
$ shellex -bg grey15 -fg linen
......
INSTALL_TARGETS += install-conf
INSTALL_TARGETS += install-conf install-rc
CLEAN_TARGETS += clean-shellexrc
ALL_TARGETS += conf/shellexrc
default_confs := 10-autoexec 40-escape 40-setprompt 40-sigint 90-hist 99-clear
default_confs := 10-autoexec 20-nobeep 40-escape 40-home_end 40-setprompt 40-sigint 90-hist 99-clear
install-conf:
echo "[INSTALL] $@"
$(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)$(LIBDIR)/shellex/conf
for file in $(wildcard conf/*); \
for file in $(wildcard conf/[0-9][0-9]-*); \
do \
$(INSTALL) -m 0644 $${file} $(DESTDIR)$(PREFIX)$(LIBDIR)/shellex/conf/; \
done
......@@ -13,3 +16,16 @@ install-conf:
do \
[ -e $(DESTDIR)$(SYSCONFDIR)/shellex/$${link} ] || ln -s $(PREFIX)$(LIBDIR)/shellex/conf/$${link} $(DESTDIR)$(SYSCONFDIR)/shellex; \
done
conf/shellexrc: conf/shellexrc.in
echo "[SED] $@"
$(SED) $(sed_replace_vars) $< > $@
install-rc: conf/shellexrc
echo "[INSTALL] $@"
$(INSTALL) -m 0644 conf/shellexrc $(DESTDIR)$(PREFIX)$(LIBDIR)/shellex/shellexrc
[ -e $(DESTDIR)$(SYSCONFDIR)/shellexrc ] || ln -s $(PREFIX)$(LIBDIR)/shellex/shellexrc $(DESTDIR)$(SYSCONFDIR)/shellexrc
clean-shellexrc:
echo "[CLEAN] conf/shellexrc"
rm -f conf/shellexrc
......@@ -7,34 +7,8 @@ function shellex_preexec () {
# In $1 the command-line is given
# In $3 the command-line with expanded aliases and function-bodies is given
# Don't do anything, if an empty command is given
if [ "$1" -regex-match '^\s*$' ]
then
return 0
fi
# We need to write the command to a temporary file to accomodate multiple
# commands (see https://github.com/Merovius/shellex/issues/11). We let the
# shell immediately remove the tempfile, so it's rather short-lived.
file=`mktemp -t shellex_exec-XXXXXXXX`
# manually write history to histfile
# this is indeed more hack, the child zsh which executes $file should do this
if [ -n "$HISTFILE" ]
then
# We write the short form of the command to history
echo "$1" >> $HISTFILE
fi
# 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
# prevent writing meaningless "zsh $file > /dev/null ...." to history
unset HISTFILE
# Execute the tempfile, then exit
zsh $file > /dev/null 2>&1 & disown
zsh -c $3 > /dev/null 2>&1 & disown
exit
}
......@@ -42,3 +16,13 @@ function shellex_preexec () {
# We use preexec_functions, so that the user can decide to overwrite our choice
# or ammend it by own functions
preexec_functions=(shellex_preexec)
# preexec doesn't get executed on empty lines, so employ zle to exit on empty lines
# https://www.reddit.com/r/zsh/comments/s6t6d/is_there_an_alias_for_an_empty_line/
function empty-buffer-to-exit() {
if [[ $#BUFFER == 0 ]]; then
BUFFER="exit"
fi
}
# set special widget, see man zshzle
zle -N zle-line-finish empty-buffer-to-exit
# disable beeping of the shellex shell. e.g. when tab-completing
# © 2016 Paul Seyfert and contributors (see also: LICENSE)
setopt NO_BEEP
......@@ -2,6 +2,7 @@
# Make zsh exit on escape
# © 2013 Axel Wagner and contributors (see also: LICENSE)
function _shellex_exit {
fc -P
exit
}
zle -N _shellex_exit
......
# vim:ft=zsh
# Make home and end buttons usable
# © 2014 Axel Wagner and contributors (see also: LICENSE)
bindkey '^[[7~' beginning-of-line
bindkey '^[[8~' end-of-line
bindkey '^[[3~' delete-char
# vim:ft=zsh
# use gksudo (or kdesudo if gksudo not exists) instead of sudo
# © 2013 Johannes Visintini and contributors (see also: LICENSE)
which kdesudo > /dev/null 2>&1 && alias sudo='kdesudo'
which gksudo > /dev/null 2>&1 && alias sudo='gksudo'
# histfile enabling and forcing to read the history after setting it
# vim:ft=zsh
# Avoid configuration sourcing in history
# © 2013 Paul Seyfert and contributors (see also: LICENSE)
setopt sharehistory
setopt appendhistory
# ensure history gets actually written (shell gets closed before history gets
# written otherwise)
setopt inc_append_history
HISTSIZE=100
HISTFILE=~/.shellex_history
SAVEHIST=100
fc -R
# Push current history to stack (make e.g. sourcing of configuration
# inaccessible to user). The stack won't be poped. Set HISTFILE to ~/.shellex
# and read history from there.
fc -p ~/.shellex_history
# vim:ft=zsh
# Source all conf files
# © 2016 Paul Seyfert and contributors (see also: LICENSE)
# get array of all relevant files
# http://stackoverflow.com/a/10981499
# http://unix.stackexchange.com/a/26825
thefiles=(@SYSCONFDIR@/shellex/* $HOME/.shellex/*(.N))
# get the basenames of all files and make unique list
# http://stackoverflow.com/a/9516801
uniquified=( $( for f in "${thefiles[@]}" ; do basename $f ; done | sort -u ) )
# source each file from $HOME/.shellex if it exists there, otherwise from /etc
for f in $uniquified
do
# -r checks if file exists and is readable
if [[ -r $HOME/.shellex/$f ]]
then
source $HOME/.shellex/$f
else
source @SYSCONFDIR@/shellex/$f
fi
done
......@@ -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.
......@@ -7,7 +7,7 @@ template::[header-declarations]
<refentrytitle>{mantitle}</refentrytitle>
<manvolnum>{manvolnum}</manvolnum>
<refmiscinfo class="source">shellex</refmiscinfo>
<refmiscinfo class="version">0.1</refmiscinfo>
<refmiscinfo class="version">0.2</refmiscinfo>
<refmiscinfo class="manual">shellex Manual</refmiscinfo>
</refmeta>
<refnamediv>
......
shellex(1)
==========
Axel Wagner <mail@merovius.de>
v0.1, August 2013
Paul Seyfert <pseyfert@mathphys.fsk.uni-heidelberg.de>
v0.2, December 2016
== NAME
......@@ -15,7 +15,7 @@ shellex - shell-based launcher
All command-line parameters (together with some shellex-specific) are passed on
to urxvt. This means, you can you e.g. '-bg grey20' for a lighter background.
Using it for more than just customizing the appearence (for example adding own
Using it for more than just customizing the appearance (for example adding own
extensions) might stop shellex from working, so be careful.
See urxvt(1) for a full list of options.
......@@ -33,16 +33,20 @@ configurable in shell.
== RESOURCES
*shellex* uses two X-Resources at the monent, to manipulate its behaviour:
*shellex* uses two X-Resources at the moment, to manipulate its behaviour:
URxvt.shellex.pos::
shellex.pos::
If pointer, shellex shows the window on the window, the mousepointer is on. If
focus, it uses the output, where most of the currently focused window is.
Defaults to focus.
URxvt.shellex.edge::
shellex.edge::
On what screen edge to show the launcher (top or bottom). Defaults to top.
Additionally all resources defined by urxvt (with class 'shellex' instead of
'urxvt') can be used to customize the appearance or behaviour of the used
terminal window.
== CONFIGURATION
*shellex* configuration snippets can be found in *@PREFIX@@LIBDIR@/shellex/*.
......
......@@ -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
......@@ -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;
}
......@@ -2,8 +2,8 @@ ALL_TARGETS += preload/shellex_preload.so
INSTALL_TARGETS += install-shellex_preload
CLEAN_TARGETS += clean-shellex_preload
SHELLEX_CFLAGS=-fPIC
SHELLEX_PRELOAD_LDFLAGS=-shared
SHELLEX_PRELOAD_LDFLAGS += -shared
SHELLEX_PRELOAD_CFLAGS += -fPIC
preload/shellex_preload.so: preload/main.c
echo "[CC] $@"
......
......@@ -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 -bg grey15 -fg linen $* -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
......@@ -2,9 +2,6 @@ ALL_TARGETS += shellex
INSTALL_TARGETS += install-shellex
CLEAN_TARGETS += clean-shellex
SHELLEX_CFLAGS=-fPIC
SHELLEX_PRELOAD_LDFLAGS=-shared
shellex: shellex.in
echo "[SED] $@"
$(SED) $(sed_replace_vars) $< > $@
......
......@@ -128,35 +128,6 @@ sub geometry_from_focus {
}
}
sub slurp {
open my $fh, '<', shift;
local $/;
<$fh>;
}
sub gen_conf {
my ($cfg, $cfgname) = tempfile("/tmp/shellex-XXXXXXXX", UNLINK => 0);
print $cfg "rm $cfgname\n";
my %fileset;
map { $fileset{basename($_)} = 1 } <@SYSCONFDIR@/shellex/*>;
map { $fileset{basename($_)} = 1 } <$ENV{HOME}/.shellex/*>;
my @files = sort keys %fileset;
for my $f (@files) {
if (-e "$ENV{HOME}/.shellex/$f") {
print $cfg slurp("$ENV{HOME}/.shellex/$f");
} else {
print $cfg slurp("@SYSCONFDIR@/shellex/$f");
}
}
close($cfg);
return $cfgname;
}
# This hook is run when the extension is first initialized, before any windows
# are created or mapped. There is not much work we can do here.
sub on_init {
......@@ -179,7 +150,13 @@ sub on_init {
sub on_start {
my ($self) = @_;
if ($self->x_resource("%.edge") eq 'bottom') {
# TODO: Remove compatibility code in future version
if (defined $self->x_resource("%.edge") || defined $self->x_resource("%.pos")) {
print "WARNING: URxvt.shellex.* resources are deprecated and will be removed in the future. Use shellex.*\n"
}
if ($self->x_resource("edge") eq 'bottom' || $self->x_resource("%.edge") eq 'bottom') {
print "position should be at the bottom\n";
$self->{bottom} = 1;
$self->{y} = $self->{h};
......@@ -187,7 +164,7 @@ sub on_start {
print "position should be at the top\n";
}
if ($self->x_resource("%.pos") eq 'pointer') {
if ($self->x_resource("pos") eq 'pointer' || $self->x_resource("%.pos") eq 'pointer') {
print "Getting shellex-position from pointer\n";
$self->geometry_from_ptr();
} else {
......@@ -197,18 +174,38 @@ 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_HEIGHT} = 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');
# the compiled-in default if the resource is not set
$self->{border} //= 2;
$self->{border} += $self->x_resource('externalBorder');
$self->{row_height} = $self->fheight + $self->x_resource('lineSpace');
my $height = $self->{row_height} + 2 * $self->{border};
my $y = $self->{y};
# Our initial position is different, if we have to be at the bottom
if ($self->{bottom}) {
$self->XMoveResizeWindow($self->parent, $self->{x}, $self->{y} - (2 + $self->fheight), $self->{w}, 2+$self->fheight);
} else {
$self->XMoveResizeWindow($self->parent, $self->{x}, $self->{y}, $self->{w}, 2+$self->fheight);
}
$y -= $height if $self->{bottom};
$self->XMoveResizeWindow($self->parent, $self->{x}, $y, $self->{w}, $height);
my $cfg = gen_conf();
print "loading config\n";
$self->tt_write($self->locale_encode("unset LD_PRELOAD\n"));
$self->tt_write($self->locale_encode(". @SYSCONFDIR@/shellexrc\n"));
$self->tt_write($self->locale_encode(". $cfg\n"));
();
}
......@@ -228,6 +225,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
......@@ -300,6 +298,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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment