The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

#!/usr/bin/env perl
# Created on: 2008-01-26 16:49:28
# Create by: freman
# $Id$
# $Revision$, $HeadURL$, $Date$
# $Revision$, $Source$, $Date$
use strict;
use version;
use Data::Dumper qw/Dumper/;
use English qw/ -no_match_vars /;
use List::MoreUtils qw/uniq/;
use Term::ANSIColor qw/colored/;
use YAML qw/LoadFile DumpFile/;
our $VERSION = version->new('0.0.8');
my ($PROGNAME) = $PROGRAM_NAME =~ m{^.*/(.*?)$}mxs;
my $HOME = $ENV{HOME};
my $SCREEN = '/usr/bin/screen';
my %option = (
task => '',
force_title => 1,
verbose => 0,
man => 0,
help => 0,
VERSION => 0,
);
my %ERROR = (
COULD_NOT_LAUNCH_SCREEN => {
message => "Unable to launch screen %s\n",
code => 10,
},
COULD_NOT_LAUNCH_SCREEN_PROTECTION => {
message => "Unable to run protection screen '%s': %s\n",
code => 12,
},
COULD_NOT_WIPE_SESSION => {
message => "Unable to launch screen to wipe '%s': %s\n",
code => 14,
},
COULD_NOT_REATTACH => {
message => "Unable to launch screen to re-attach to '%s': %s\n",
code => 16,
},
COULD_NOT_FIND_SESSION => {
message => "Could not find the screen session '%s'\n",
code => 18,
},
COULD_NOT_FIND_CONFIG => {
message => "No config exists for %s\nTo create from template Use:\n \$ %s %s --create\n",
code => 20,
},
COULD_NOT_LAUNCH_SCREEN_TASK => {
message => "Unable to launch screen for '%s': %s\n",
code => 30,
},
COULD_NOT_CREATE_CONFIG => {
message => "Could not create '%s' config from template: %s\n",
code => 40,
},
);
my %COLOURS = (
'ATTACHED' => 'green',
'DETACHED' => 'blue',
'Not Started' => 'white',
'' => 'red',
);
my %SUFFIXES = (
'ATTACHED' => '*',
'DETACHED' => '/',
'Not Started' => '',
'' => '',
);
if (!@ARGV) {
pod2usage(-verbose => 1);
}
main();
exit 0;
sub error {
my ( $name, @args ) = @_;
print {*STDERR} sprintf $ERROR{$name}{message}, @args;
exit $ERROR{$name}{code};
}
sub main {
Getopt::Long::Configure('bundling');
GetOptions(
\%option,
'task|t=s',
'kill|k',
'list|ls|l',
'bw',
'all|a',
'exists|e!',
'multiconnect|x',
'create|c+',
'chdir|d',
'reconnect|r!',
'force_title|force-title|f',
'title_bar|title-bar|b=s',
'protect|p',
'short|S!',
'server|s=s',
'auto|A=s',
'current|C=s',
'remote_opt|remote-opt|o=s',
'pre_cmd|pre-cmd|pre=s',
'post_cmd|post-cmd|post=s',
'test|T',
'verbose|v+',
'man',
'help',
'VERSION!',
) or pod2usage(2);
my $task = $option{task} || $ARGV[0] || '';
if ($option{VERSION}) {
print "$PROGNAME Version = $VERSION\n";
exit 1;
}
elsif ($option{man}) {
pod2usage(-verbose => 2);
}
elsif ($option{help}) {
pod2usage(-verbose => 1);
}
elsif ( $option{auto} ) {
auto($option{auto}) ;
}
my %session = get_sessions();
# Make upper and lower case versions of the task name
# All filenames are lower case
# All session names are upper case
my $uc_task = uc $task;
my $lc_task = lc $task;
# task defaults
my $config = config($lc_task);
if ($option{'server'}) {
my $mode = shift @ARGV;
my $reset = 'reset;';
my $ssh = 'ssh -t';
if ( $option{list} ) {
$mode = '--list';
$reset = '';
$ssh = 'ssh';
}
push @ARGV, $config->{remote_opt} if $config->{remote_opt};
return print "$ssh @ARGV $option{server} '$reset devmode $mode'\n" if $option{test};
return exec "$ssh @ARGV $option{server} '$reset devmode $mode'";
}
elsif ($option{'list'}) {
my $count = 0;
if ( $option{verbose} || $option{all} ) {
my @modes = grep { -f $_ && $_->basename !~ /^[.#]|[.]rc$/xms } dir("$ENV{HOME}", ".devmode")->children;
for my $mode (@modes) {
my $base = $mode->basename;
$session{uc $base} ||= { state => 'Not Started' };
}
}
SESSION:
for my $session ( sort keys %session ) {
# remove any sessions that look like they are named after their pid
next SESSION if $session{$session}{pid} && $session =~ /^\d+$/ && $session == $session{$session}{pid};
print ucfirst lc $session{$session}{state},
' ' x (14 - length $session{$session}{state}),
$option{bw}
? lc $session
: colored( lc $session, $COLOURS{ $session{$session}{state} || '' } ),
"\n";
$count++;
}
exit $count;
}
if ( $option{create} && !-f "$HOME/.devmode/$lc_task" ) {
my $task = create_task( $task, $option{template} || 'rc', "$ENV{HOME}/.devmode/" );
exec 'vim', $task;
}
if ($config) {
for my $key ( keys %{ $config } ) {
if ( !exists $option{$key} ) {
$option{$key} = $config->{$key};
}
}
}
if ($option{'force_title'}) {
force_title( $option{title_bar} || $task);
}
else {
$option{short} = length $task > 8 if !exists $option{short};
require Term::Title;
Term::Title::set_titlebar(
( $option{short} ? '' : "Devmode " )
. ( $option{title_bar} || $task )
);
}
if ( $option{verbose} ) {
print Dumper \%session;
}
if ( exists $session{$uc_task} ) {
if ( $option{kill} ) {
if ( $option{post_cmd} ) {
system $option{post_cmd};
}
system "kill $session{$uc_task}{pid}";
exit;
}
elsif ( $session{$uc_task}{state} eq 'DEAD' ) {
warn "A previous session for '$task' was detected as dead, wiping and starting a new session\n";
system "$SCREEN -wipe $uc_task > /dev/null 2>&1" or error( COULD_NOT_WIPE_SESSION => $task, $OS_ERROR );
}
else {
my $task = "$session{$uc_task}{pid}.$uc_task";
my $conn = $option{multiconnect} ? '-x' : '-d -R';
warn "$SCREEN $conn $task" if $option{verbose} || $option{test};
return if $option{test};
exec "$SCREEN $conn $task" or error( COULD_NOT_REATTACH => $task, $OS_ERROR );
}
}
elsif ( $option{reconnect} || $option{kill} ) {
error( COULD_NOT_FIND_SESSION => $task );
}
system $option{pre_cmds} if $option{pre_cmds};
my @screen_opts = (
"-S $uc_task",
);
# Per session config?
if (-e "$HOME/.devmode/$lc_task") {
push @screen_opts, "-c $HOME/.devmode/$lc_task";
if ($option{chdir}) {
my $rc = file("$HOME/.devmode/$lc_task")->slurp;
my ($dir) = $rc =~ m{ ^ chdir \s+ (\S+?) $ }xms;
if ( -d $dir ) {
chdir $dir;
}
}
}
elsif ( $option{exits} ) {
error( COULD_NOT_FIND_CONFIG => $task, $0, $task );
die "No config exists for $task\nTo create from template Use:\n \$ $0 $task --create\n";
}
if ( $option{protect} ) {
protect($lc_task);
}
if ( $option{pre_cmd} ) {
system $option{pre_cmd};
}
my $cmd = "$SCREEN " . join (' ', @screen_opts);
if ($option{test}) {
warn $cmd;
exit 0;
}
exec $cmd or error( COULD_NOT_LAUNCH_SCREEN_TASK => $task, $OS_ERROR );
}
sub get_sessions {
my %session;
# run screen to read in all the sessions
open my $screen, "-|", "$SCREEN -ls" or error( COULD_NOT_LAUNCH_SCREEN => $OS_ERROR);
# read each running session
while ( my $session = <$screen> ) {
if ( $session =~ /^\s+ (\d+) [.] ([\w-]+) \s+ (?: \( .*? \) \s+ )? \( (Attached|Dead|Detached) /xms ) {
$session{$2} = {
pid => $1,
name => $2,
state => uc($3),
};
$session{$1} = $session{$2}
}
}
close $screen;
return map { $_ => $session{$_} } grep { $_ ne $session{$_}{pid} } keys %session;
}
# runs a ssh-agent protecting screen session
sub protect {
my ($task) = @_;
my $protect_dir = "$ENV{HOME}/.devmode_prot";
if ( !-d $protect_dir ) {
mkdir $protect_dir;
}
my $protect_rc = file $protect_dir, $task;
if ( !-f $protect_rc ) {
create_task( $task, 'rcprot', $protect_dir );
}
for my $env ( keys %ENV ) {
delete $ENV{$env} if $env =~ /ssh/i;
}
my $cmd = "$SCREEN -S PROT_$task -c $protect_rc";
if ($option{test}) {
warn $cmd;
exit 0;
}
exec $cmd or error( COULD_NOT_LAUNCH_SCREEN_PROTECTION => $cmd, $OS_ERROR );
}
sub force_title {
my ($task) = @_;
require Term::Title;
Term::Title::set_titlebar(
( $option{short} ? '' : "Devmode " )
. ( $option{title_bar} || $task )
);
return;
}
sub create_task {
my ( $task, $template, $out_dir ) = @_;
require Template;
# Create the provider
my $provider = Template::Provider::FromDATA->new({
CLASSES => __PACKAGE__,
});
# Add the provider to the config
my $tt = Template->new({
LOAD_TEMPLATES => [ $provider ],
OUTPUT_PATH => $out_dir,
});
my %data = (
cwd => file('.')->absolute->resolve,
devmode => file($0)->absolute->resolve,
task => $task,
);
$tt->process( $template, \%data, lc $task ) or error( COULD_NOT_CREATE_CONFIG => $tt->error() );
return "$out_dir/$task";
}
sub auto {
my ($type) = @_;
if ( $type eq 'ssh' ) {
my @hosts
= map {
/(.*?)(?:#.*)?$/;
my ($addr, @a) = split /\s+/, $1;
@a;
}
grep {
!/^\s*$/ && !/^\s*#/
}
map {
/(.*)\n/;
$1 || $_
}
file('/etc/hosts')->slurp;
push @hosts,
map {
/(?:Host\s*)?(.*)/;
$1;
}
grep {
/^Host /
}
map {
/(.*)\n/;
$1 || $_
}
file("$ENV{HOME}/.ssh/config")->slurp;
print join ' ', uniq sort @hosts;
exit 0;
}
elsif ( $type eq 'full' ) {
my @names;
my @running;
if ( $option{server} ) {
@names = remote_cache($option{server});
}
else {
@names
= sort {
my $A = $a;
$A =~ s/(\d+)/sprintf "%05d", $1/egxms;
my $B = $b;
$B =~ s/(\d+)/sprintf "%05d", $1/egxms;
$A cmp $B;
}
map {
$_->basename
}
grep {
!/[.]rc$/ && !/^#/
}
dir($ENV{HOME}, '.devmode')->children;
@running = `devmode --list --bw`;
}
if ( @running && !$option{bw} ) {
my %running
= map {
chomp;
my ($state, $mode) = split /\s+/, $_, 2;
( $mode => $state );
}
@running;
@names
= map {
$running{$_} ? $_ . ( $SUFFIXES{ $running{$_} || '' } || '' ) : $_;
}
@names;
}
shift @ARGV;
my $search = pop @ARGV;
if ($search) {
@names = grep { /$search/ } @names;
}
print join ' ', @names;
exit 0;
}
exit 1;
}
sub remote_cache {
my ($server) = @_;
my $cache = {};
my $cache_file = file('/tmp/devmode_remoter_cache');
if ( -f $cache_file ) {
$cache = LoadFile($cache_file);
}
# check the cache is fresh (1 day)
if ( $cache->{$server} && $cache->{$server}{last} > time - 1 * 24 * 60 * 60 ) {
return @{ $cache->{$server}{modes} };
}
$cache->{$server}{last} = time;
$cache->{$server}{modes}
= [
grep {
!/[.]rc$/ && !/^#/
}
map {
m{^(?:.*/)(.*)};
$1
}
split /\n/,
'' . `ssh $option{server} '/bin/ls -1 ~/.devmode/[^.#]*'`
];
DumpFile($cache_file, $cache);
return @{ $cache->{$server}{modes} };
}
sub config {
my ($base) = @_;
my $base_config = "$HOME/.devmode/$base.rc";
my $devmode = "$HOME/.devmode.rc";
my $config = {};
if ( -e $base_config ) {
$config = eval { LoadFile($base_config) };
# if no config found and we have an error assume that the file is old
# format and try to require it and convert to YAML.
if ( !$config && $@ ) {
$config = require $base_config;
DumpFile($base_config, $config);
}
}
if ( -e $devmode ) {
$config = { %{ LoadFile($devmode) }, %$config };
}
return $config
}
=head1 NAME
devmode - Wrapper for GNU screen to manage multiple screenrc files
=head1 VERSION
This documentation refers to devmode version 0.0.8.
=head1 SYNOPSIS
devmode <task>
OPTIONS:
<task> The name of a screen config found in the ~/.devmode/ directory
-k --kill Kill the task
-l --list List all running devmode tasks
-a --all Makes --list show even non-running sessions
-e --exists Only run screen if a devmode file exists by that name
-x --multiconnect
Connect to session with out disconnecting existing session
-c --create Creates a missing devmode task
-d --chdir Parse the config and change directory to the last chdir command
found in there.
-f --force-title
Try harder to set the terminal title
-t --template=name
Uses this template name for creating the missing task. The
default template is rc other templates can be stored in the
$HOME/.devmode/templates/ directory
-p --protect Run a surrounding screen session to protect the intended
session from ssh-agent being lost when logging out of the
of box. (experimental 256 colours doesn't work is sub screen)
-s --server=str
Use a remote server to connect to and run devmode. The server
may include username@ to login with a particular user.
-S --short Don't show "Devmode" in the title bar
-A --auto=str
Allows a BASH command line completion mode helper mode to run
-T --test Don't run any external commands
--VERSION Prints the version information
--help Prints this help information
--man Prints the full documentation for devmode
=head1 DESCRIPTION
C<devmode> makes managing screen sessions simpler by managing session names
and configuration files.
C<devmode> configuration files are stored in the $HOME/.devmode/ directory.
Templates for creating new configuration files can be placed in the directory
$HOME/.devmode/template/, the default template creates a session that always
opens to the directory that devmode was run from, it is aimed at working with
perl packages.
=head2 BASH auto-completion
_devmode() {
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="--task -t --kill -k --list --ls -l --all -a --exists -e --multiconnect -x --create -c --chdir -d --reconnect -r --force_title -force-title -f --title_bar -title-bar -b --protect -p --short -S --server -s --auto -A --current -C --pre_cmd -pre-cmd --pre --post_cmd -post-cmd --post --test -T --verbose -v --man --help --VERSION"
if [[ ${cur} == -* && ${COMP_CWORD} -eq 1 ]]; then
COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
elif [[ ${prev} == -s* ]]; then
local hosts=$(devmode --auto ssh)
COMPREPLY=($(compgen -W "${hosts}" -- ${cur}))
else
local sonames=$(devmode --auto full --current ${COMP_CWORD} ${COMP_WORDS[@]})
COMPREPLY=($(compgen -W "${sonames}" -- ${cur}))
fi
}
complete -F _devmode devmode
=head1 SUBROUTINES/METHODS
=head1 DIAGNOSTICS
=head1 CONFIGURATION AND ENVIRONMENT
The <Cdevmode> program uses 3 different types of configuration files:
=over 4
=item Screen
Stored in C<~/.devmode/[name]> are standard GNU Screen files.
=item mode
Each mode file can have a C,~/.devmode[mode].rc> to change default configuration.
It is stored in YAML format.
=item global
Stored inC<`/.devmode.rc> sets global defaults.
It is stored in YAML format.
=back
=head1 DEPENDENCIES
=head1 INCOMPATIBILITIES
=head1 BUGS AND LIMITATIONS
There are no known bugs in this module.
Please report problems to Ivan Wills (ivan.wills@gmail.com)
Patches are welcome.
=head1 AUTHOR
Shannon Wynter - (http://fremnet.net/contact) (original)
Ivan Wills - (ivan.wills@gmail.com)
=head1 LICENSE AND COPYRIGHT
Copyright (c) 2007 Shannon Wynter, 2007-2013 Ivan Wills.
All rights reserved.
=cut
__DATA__
__rc__
[% TAGS <+ +> -%]
#
# Example of a user's .screenrc file
#
# This is how one can set a reattach password:
# password ODSJQf.4IJN7E # "1234"
# no annoying audible bell, please
vbell off
# detach on hangup
autodetach on
# don't display the copyright page
startup_message off
# emulate .logout message
pow_detach_msg "Screen session of \$LOGNAME \$:cr:\$:nl:ended."
# advertise hardstatus support to $TERMCAP
# termcapinfo * '' 'hs:ts=\E_:fs=\E\\:ds=\E_\E\\'
# make the shell in every window a login shell
#shell -$SHELL
# autoaka testing
# shellaka '> |tcsh'
# shellaka '$ |sh'
# set every new windows hardstatus line to somenthing descriptive
# defhstatus "screen: ^En (^Et)"
defscrollback 5000
# don't kill window after the process died
# zombie "^["
zombie kr
################
#
# xterm tweaks
#
#xterm understands both im/ic and doesn't have a status line.
#Note: Do not specify im and ic in the real termcap/info file as
#some programs (e.g. vi) will not work anymore.
termcap xterm hs@:cs=\E[%i%d;%dr:im=\E[4h:ei=\E[4l
terminfo xterm hs@:cs=\E[%i%p1%d;%p2%dr:im=\E[4h:ei=\E[4l
#80/132 column switching must be enabled for ^AW to work
#change init sequence to not switch width
termcapinfo xterm Z0=\E[?3h:Z1=\E[?3l:is=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;4;6l
# Make the output buffer large for (fast) xterms.
termcapinfo xterm* OL=10000
# tell screen that xterm can switch to dark background and has function
# keys.
termcapinfo xterm 'VR=\E[?5h:VN=\E[?5l'
termcapinfo xterm 'k1=\E[11~:k2=\E[12~:k3=\E[13~:k4=\E[14~'
termcapinfo xterm 'kh=\E[1~:kI=\E[2~:kD=\E[3~:kH=\E[4~:kP=\E[H:kN=\E[6~'
# special xterm hardstatus: use the window title.
#termcapinfo xterm 'hs:ts=\E]2;:fs=\007:ds=\E]2;screen\007'
#terminfo xterm 'vb=\E[?5h$<200/>\E[?5l'
termcapinfo xterm 'vi=\E[?25l:ve=\E[34h\E[?25h:vs=\E[34l'
# emulate part of the 'K' charset
termcapinfo xterm 'XC=K%,%\E(B,[\304,\\\\\326,]\334,{\344,|\366,}\374,~\337'
# xterm-52 tweaks:
# - uses background color for delete operations
termcapinfo xterm ut
################
#
# wyse terminals
#
#wyse-75-42 must have flow control (xo = "terminal uses xon/xoff")
#essential to have it here, as this is a slow terminal.
termcapinfo wy75-42 xo:hs@
# New termcap sequences for cursor application mode.
termcapinfo wy* CS=\E[?1h:CE=\E[?1l:vi=\E[?25l:ve=\E[?25h:VR=\E[?5h:VN=\E[?5l:cb=\E[1K:CD=\E[1J
################
#
# other terminals
#
#make hp700 termcap/info better
termcapinfo hp700 'Z0=\E[?3h:Z1=\E[?3l:hs:ts=\E[62"p\E[0$~\E[2$~\E[1$}:fs=\E[0}\E[61"p:ds=\E[62"p\E[1$~\E[61"p:ic@'
# Extend the vt100 desciption by some sequences.
termcap vt100* ms:AL=\E[%dL:DL=\E[%dM:UP=\E[%dA:DO=\E[%dB:LE=\E[%dD:RI=\E[%dC
terminfo vt100* ms:AL=\E[%p1%dL:DL=\E[%p1%dM:UP=\E[%p1%dA:DO=\E[%p1%dB:LE=\E[%p1%dD:RI=\E[%p1%dC
# 256 colour stuff
# terminfo and termcap for nice 256 color terminal
# allow bold colors - necessary for some reason
attrcolor b ".I"
# tell screen how to set colors. AB = background, AF=foreground
termcapinfo xterm 'Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm'
# erase background with current bg color
#defbce "on"
################
#
# keybindings
#
#remove some stupid / dangerous key bindings
bind k
bind ^k
bind .
bind ^\
bind \\
bind ^h
bind h
#make them better
bind 'K' kill
bind 'I' login on
bind 'O' login off
bind '}' history
# Yet another hack:
# Prepend/append register [/] to the paste if ^a^] is pressed.
# This lets me have autoindent mode in vi.
register [ "\033:se noai\015a"
register ] "\033:se ai\015a"
bind ^] paste [.]
################
#
# default windows
#
# screen -t local 0
# screen -t mail 1 elm
# screen -t 40 2 rlogin faui40
# caption always "%3 %t%? @%u%?%? [%h]%?"
# hardstatus alwaysignore
# hardstatus alwayslastline "%w"
# run any cmds before starting the screen session
# eg cd via chdir
# choose a program to run automaticall in that window by appending to the end of the command
#
# eg:
# chdir /var/log/apache
# screen -t 'logs' 1 tail -f error_log
#
chdir <+ cwd +>
screen -t '> cmds' 1
screen -t '> cmds' 2
screen -t '> code' 3
screen -t '> code' 4 #deep -N10 -fbd data=1 /tmp/<+ task +>_\*.log
screen -t '> code' 5 itail /www/logs/error.log /www/logs/access.log
chdir <+ cwd +>/db
screen -t '> psql' 6
chdir <+ cwd +>
screen -t '> root' 7 sudo -s
#screen -t '> tail' 8
#screen -t '> code' 9
#screen -t '> code' 10
#screen -t '> code' 11
#screen -t '> code' 12
#screen -t '> code' 13
#screen -t '> code' 14
#screen -t '> code' 15
#screen -t '> code' 16
#screen -t '> code' 17
#screen -t '> code' 18
#screen -t '> code' 19
#screen -t '> code' 20
#screen -t '> code' 21
#screen -t '> code' 22
# see 'Input Translation' section for key names
bindkey 0 select 0
bindkey OP select 1
bindkey OQ select 2
bindkey OR select 3
bindkey OS select 4
bindkey -k k5 select 5
bindkey -k k6 select 6
bindkey -k k7 select 7
bindkey -k k8 select 8
bindkey -k k9 select 9
bindkey -k k; select 10
bindkey -k F1 select 11
bindkey -k F2 select 12
bindkey 3 select 13
bindkey 4 select 14
bindkey 5 select 15
bindkey 6 select 16
bindkey 7 select 17
bindkey 8 select 18
bindkey 9 select 19
bindkey 0 select 20
bindkey 1 select 21
bindkey 2 select 22
hardstatus on
hardstatus alwayslastline
#hardstatus string "%{..k}%-t%{.rK}%n %t%{-}%+w %=%{..K} %H %{..K} %Y-%m-%d %c "
#hardstatus alwayslastline "%-Lw%{= BW}%50>%n%f* %t%{-}%+Lw%< %=[%c, %D, %d/%m/%y]"
#hardstatus alwayslastline "%-w%?%F%{.R.}%?%n %t%+w [%H %l] [%0c] [%Y-%m-%d]"
hardstatus alwayslastline "%{+b}%{.kw}[<+ task +>] %-w%{.kc}%n %t%{-}%+w %=%{b}%H%{d} - %{y}%l%{d} - %{r}%Y-%m-%d %0c"
#caption always "%{=}%?%{r}%H %L=%{+b}%?%{b}%-Lw%47L>%?%{w}%n*%f %t %?%{b}%+Lw%?%{g}%-31=%c %l %Y-%m-%d"
escape ^Aa
__rcprot__
[% TAGS <+ +> -%]
vbell off
autodetach on
startup_message off
pow_detach_msg "Screen session of \$LOGNAME \$:cr:\$:nl:ended."
defscrollback 0
termcap xterm hs@:cs=\E[%i%d;%dr:im=\E[4h:ei=\E[4l
terminfo xterm hs@:cs=\E[%i%p1%d;%p2%dr:im=\E[4h:ei=\E[4l
termcapinfo xterm Z0=\E[?3h:Z1=\E[?3l:is=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;4;6l
termcapinfo xterm* OL=10000
termcapinfo xterm 'VR=\E[?5h:VN=\E[?5l'
termcapinfo xterm 'k1=\E[11~:k2=\E[12~:k3=\E[13~:k4=\E[14~'
termcapinfo xterm 'kh=\E[1~:kI=\E[2~:kD=\E[3~:kH=\E[4~:kP=\E[H:kN=\E[6~'
termcapinfo xterm 'vi=\E[?25l:ve=\E[34h\E[?25h:vs=\E[34l'
termcapinfo xterm 'XC=K%,%\E(B,[\304,\\\\\326,]\334,{\344,|\366,}\374,~\337'
termcapinfo xterm ut
termcapinfo wy75-42 xo:hs@
termcapinfo wy* CS=\E[?1h:CE=\E[?1l:vi=\E[?25l:ve=\E[?25h:VR=\E[?5h:VN=\E[?5l:cb=\E[1K:CD=\E[1J
termcapinfo hp700 'Z0=\E[?3h:Z1=\E[?3l:hs:ts=\E[62"p\E[0$~\E[2$~\E[1$}:fs=\E[0}\E[61"p:ds=\E[62"p\E[1$~\E[61"p:ic@'
termcap vt100* ms:AL=\E[%dL:DL=\E[%dM:UP=\E[%dA:DO=\E[%dB:LE=\E[%dD:RI=\E[%dC
terminfo vt100* ms:AL=\E[%p1%dL:DL=\E[%p1%dM:UP=\E[%p1%dA:DO=\E[%p1%dB:LE=\E[%p1%dD:RI=\E[%p1%dC
attrcolor b ".I"
termcapinfo xterm 'Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm'
bind k
bind ^k
bind .
bind ^\
bind \\
bind ^h
bind h
#make them better
bind 'K' kill
bind 'I' login on
bind 'O' login off
bind '}' history
register [ "\033:se noai\015a"
register ] "\033:se ai\015a"
bind ^] paste [.]
escape ^Qq
screen 0 bash -c 'ssh-agent; <+ devmode +> <+ task +>'