Use TERM env var / terminfo to decide whether to send ECH. Fixes tmux bug.
Closes #28 github issue.
This commit is contained in:
@@ -88,6 +88,7 @@ Getting Mosh
|
||||
* [GNU Autotools][]
|
||||
* the [Protocol Buffers][] library and compiler
|
||||
* [Boost][]
|
||||
* `ncurses`
|
||||
* `libutempter`
|
||||
* `zlib`
|
||||
* the Perl module [IO::Pty][]
|
||||
|
||||
+3
-1
@@ -75,7 +75,7 @@ AS_IF([test x"$with_skalibs" != xno],
|
||||
AC_SUBST([STDDJB_LDFLAGS], ["$SKALIBS_LDFLAGS -lstddjb"])])
|
||||
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([arpa/inet.h fcntl.h langinfo.h limits.h locale.h netinet/in.h pty.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h termios.h unistd.h util.h wchar.h wctype.h])
|
||||
AC_CHECK_HEADERS([arpa/inet.h curses.h fcntl.h langinfo.h limits.h locale.h netinet/in.h pty.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h term.h termios.h unistd.h util.h wchar.h wctype.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_HEADER_STDBOOL
|
||||
@@ -99,6 +99,8 @@ AC_CHECK_FUNCS([gettimeofday inet_ntoa iswprint memchr memset nl_langinfo setenv
|
||||
|
||||
AC_SEARCH_LIBS([clock_gettime], [rt], [AC_DEFINE([HAVE_CLOCK_GETTIME], [1], [Define if clock_gettime is available.])])
|
||||
|
||||
AC_CHECK_LIB([ncurses], [setupterm])
|
||||
|
||||
AC_CHECK_DECL([mach_absolute_time],
|
||||
[AC_DEFINE([HAVE_MACH_ABSOLUTE_TIME], [1],
|
||||
[Define if mach_absolute_time is available.])],
|
||||
|
||||
Vendored
+1
-1
@@ -2,7 +2,7 @@ Source: mosh
|
||||
Section: net
|
||||
Priority: optional
|
||||
Maintainer: Keith Winstein <keithw@mit.edu>
|
||||
Build-Depends: debhelper (>= 7.0.50), autotools-dev, protobuf-compiler, libprotobuf-dev, dh-autoreconf, pkg-config, libutempter-dev, libboost-dev, zlib1g-dev, skalibs-dev
|
||||
Build-Depends: debhelper (>= 7.0.50), autotools-dev, protobuf-compiler, libprotobuf-dev, dh-autoreconf, pkg-config, libutempter-dev, libboost-dev, zlib1g-dev, skalibs-dev, libncurses5-dev
|
||||
Standards-Version: 3.9.3
|
||||
Homepage: http://mosh.mit.edu
|
||||
Vcs-Git: git://github.com/keithw/mosh.git
|
||||
|
||||
@@ -148,7 +148,8 @@ int main( void )
|
||||
}
|
||||
|
||||
/* Print a frame if the last frame was more than 1/50 seconds ago */
|
||||
bool tick( Terminal::Framebuffer &state, const Terminal::Framebuffer &new_frame )
|
||||
bool tick( Terminal::Framebuffer &state, const Terminal::Framebuffer &new_frame,
|
||||
const Terminal::Display &display )
|
||||
{
|
||||
static bool initialized = false;
|
||||
static struct timeval last_time;
|
||||
@@ -164,7 +165,7 @@ bool tick( Terminal::Framebuffer &state, const Terminal::Framebuffer &new_frame
|
||||
|
||||
if ( (!initialized)
|
||||
|| (diff >= 0.02) ) {
|
||||
std::string update = Terminal::Display::new_frame( initialized, state, new_frame );
|
||||
std::string update = display.new_frame( initialized, state, new_frame );
|
||||
swrite( STDOUT_FILENO, update.c_str() );
|
||||
state = new_frame;
|
||||
|
||||
@@ -222,6 +223,9 @@ void emulate_terminal( int fd )
|
||||
Terminal::Complete complete( window_size.ws_col, window_size.ws_row );
|
||||
Terminal::Framebuffer state( window_size.ws_col, window_size.ws_row );
|
||||
|
||||
/* open display */
|
||||
Terminal::Display display( true ); /* use TERM to initialize */
|
||||
|
||||
struct pollfd pollfds[ 3 ];
|
||||
|
||||
pollfds[ 0 ].fd = STDIN_FILENO;
|
||||
@@ -310,14 +314,14 @@ void emulate_terminal( int fd )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( tick( state, complete.get_fb()) ) { /* there was a frame */
|
||||
if ( tick( state, complete.get_fb(), display ) ) { /* there was a frame */
|
||||
poll_timeout = -1;
|
||||
} else {
|
||||
poll_timeout = 20;
|
||||
}
|
||||
}
|
||||
|
||||
std::string update = Terminal::Display::new_frame( true, state, complete.get_fb() );
|
||||
std::string update = display.new_frame( true, state, complete.get_fb() );
|
||||
swrite( STDOUT_FILENO, update.c_str() );
|
||||
|
||||
swrite( STDOUT_FILENO, Terminal::Emulator::close().c_str() );
|
||||
|
||||
@@ -89,6 +89,8 @@ int main( int argc, char *argv[] )
|
||||
} catch ( Crypto::CryptoException e ) {
|
||||
fprintf( stderr, "Crypto exception: %s\r\n",
|
||||
e.text.c_str() );
|
||||
} catch ( std::string s ) {
|
||||
fprintf( stderr, "Error: %s\r\n", s.c_str() );
|
||||
}
|
||||
|
||||
printf( "\n[mosh is exiting.]\n" );
|
||||
|
||||
@@ -130,7 +130,7 @@ void STMClient::main_init( void )
|
||||
local_framebuffer = new Terminal::Framebuffer( window_size.ws_col, window_size.ws_row );
|
||||
|
||||
/* initialize screen */
|
||||
string init = Terminal::Display::new_frame( false, *local_framebuffer, *local_framebuffer );
|
||||
string init = display.new_frame( false, *local_framebuffer, *local_framebuffer );
|
||||
swrite( STDOUT_FILENO, init.data(), init.size() );
|
||||
|
||||
/* open network */
|
||||
@@ -158,7 +158,7 @@ void STMClient::output_new_frame( void )
|
||||
overlays.apply( new_state );
|
||||
|
||||
/* calculate minimal difference from where we are */
|
||||
const string diff( Terminal::Display::new_frame( !repaint_requested,
|
||||
const string diff( display.new_frame( !repaint_requested,
|
||||
*local_framebuffer,
|
||||
new_state ) );
|
||||
swrite( STDOUT_FILENO, diff.data(), diff.size() );
|
||||
|
||||
@@ -42,6 +42,7 @@ private:
|
||||
Terminal::Framebuffer *local_framebuffer;
|
||||
Overlay::OverlayManager overlays;
|
||||
Network::Transport< Network::UserStream, Terminal::Complete > *network;
|
||||
Terminal::Display display;
|
||||
|
||||
bool repaint_requested, quit_sequence_started;
|
||||
|
||||
@@ -61,6 +62,7 @@ public:
|
||||
local_framebuffer( NULL ),
|
||||
overlays(),
|
||||
network( NULL ),
|
||||
display( true ), /* use TERM environment var to initialize display */
|
||||
repaint_requested( false ),
|
||||
quit_sequence_started( false )
|
||||
{
|
||||
|
||||
@@ -75,7 +75,7 @@ string Complete::diff_from( const Complete &existing ) const
|
||||
new_res->MutableExtension( resize )->set_height( terminal.get_fb().ds.get_height() );
|
||||
}
|
||||
Instruction *new_inst = output.add_instruction();
|
||||
new_inst->MutableExtension( hostbytes )->set_hoststring( Terminal::Display::new_frame( true, existing.get_fb(), terminal.get_fb() ) );
|
||||
new_inst->MutableExtension( hostbytes )->set_hoststring( display.new_frame( true, existing.get_fb(), terminal.get_fb() ) );
|
||||
}
|
||||
|
||||
return output.SerializeAsString();
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace Terminal {
|
||||
private:
|
||||
Parser::UTF8Parser parser;
|
||||
Terminal::Emulator terminal;
|
||||
Terminal::Display display;
|
||||
|
||||
std::list< std::pair<uint64_t, uint64_t> > input_history;
|
||||
uint64_t echo_ack;
|
||||
@@ -39,7 +40,7 @@ namespace Terminal {
|
||||
static const int ECHO_TIMEOUT = 50; /* for late ack */
|
||||
|
||||
public:
|
||||
Complete( size_t width, size_t height ) : parser(), terminal( width, height ),
|
||||
Complete( size_t width, size_t height ) : parser(), terminal( width, height ), display( false ),
|
||||
input_history(), echo_ack( 0 ) {}
|
||||
|
||||
std::string act( const std::string &str );
|
||||
|
||||
@@ -3,5 +3,4 @@ AM_CXXFLAGS = $(WARNING_CXXFLAGS) $(PICKY_CXXFLAGS) -fno-default-inline -pipe
|
||||
|
||||
noinst_LIBRARIES = libmoshterminal.a
|
||||
|
||||
libmoshterminal_a_SOURCES = parseraction.cc parseraction.h parser.cc parser.h parserstate.cc parserstatefamily.h parserstate.h parsertransition.h terminal.cc terminaldispatcher.cc terminaldispatcher.h terminaldisplay.cc terminaldisplay.h terminalframebuffer.cc terminalframebuffer.h terminalfunctions.cc terminal.h terminaluserinput.cc terminaluserinput.h
|
||||
|
||||
libmoshterminal_a_SOURCES = parseraction.cc parseraction.h parser.cc parser.h parserstate.cc parserstatefamily.h parserstate.h parsertransition.h terminal.cc terminaldispatcher.cc terminaldispatcher.h terminaldisplay.cc terminaldisplayinit.cc terminaldisplay.h terminalframebuffer.cc terminalframebuffer.h terminalfunctions.cc terminal.h terminaluserinput.cc terminaluserinput.h
|
||||
|
||||
@@ -25,7 +25,7 @@ using namespace Terminal;
|
||||
|
||||
/* Print a new "frame" to the terminal, using ANSI/ECMA-48 escape codes. */
|
||||
|
||||
std::string Display::new_frame( bool initialized, const Framebuffer &last, const Framebuffer &f )
|
||||
std::string Display::new_frame( bool initialized, const Framebuffer &last, const Framebuffer &f ) const
|
||||
{
|
||||
FrameState frame( last );
|
||||
|
||||
@@ -201,7 +201,7 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
|
||||
return frame.str;
|
||||
}
|
||||
|
||||
void Display::put_cell( bool initialized, FrameState &frame, const Framebuffer &f )
|
||||
void Display::put_cell( bool initialized, FrameState &frame, const Framebuffer &f ) const
|
||||
{
|
||||
char tmp[ 64 ];
|
||||
|
||||
@@ -238,13 +238,28 @@ void Display::put_cell( bool initialized, FrameState &frame, const Framebuffer &
|
||||
}
|
||||
}
|
||||
|
||||
frame.x += clear_count;
|
||||
if ( frame.x >= f.ds.get_width() ) {
|
||||
assert( frame.x + clear_count <= f.ds.get_width() );
|
||||
|
||||
/* can we go to the end of the line? */
|
||||
if ( frame.x + clear_count == f.ds.get_width() ) {
|
||||
snprintf( tmp, 64, "\033[K" );
|
||||
frame.append( tmp );
|
||||
frame.x += clear_count;
|
||||
} else {
|
||||
if ( has_ech ) {
|
||||
if ( clear_count == 1 ) {
|
||||
frame.append( "\033[X" );
|
||||
} else {
|
||||
snprintf( tmp, 64, "\033[%dX", clear_count );
|
||||
}
|
||||
frame.append( tmp );
|
||||
}
|
||||
frame.x += clear_count;
|
||||
} else { /* no ECH, so just print a space */
|
||||
frame.append( " " );
|
||||
frame.cursor_x++;
|
||||
frame.x++;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,10 +49,15 @@ namespace Terminal {
|
||||
|
||||
class Display {
|
||||
private:
|
||||
static void put_cell( bool initialized, FrameState &frame, const Framebuffer &f );
|
||||
bool has_ech; /* erase character is part of vt200 but not supported by tmux
|
||||
(or by "screen" terminfo entry, which is what tmux advertises) */
|
||||
|
||||
void put_cell( bool initialized, FrameState &frame, const Framebuffer &f ) const;
|
||||
|
||||
public:
|
||||
static std::string new_frame( bool initialized, const Framebuffer &last, const Framebuffer &f );
|
||||
std::string new_frame( bool initialized, const Framebuffer &last, const Framebuffer &f ) const;
|
||||
|
||||
Display( bool use_environment );
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Mosh: the mobile shell
|
||||
Copyright 2012 Keith Winstein
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This is in its own file because otherwise the ncurses #defines
|
||||
alias our own variable names. */
|
||||
|
||||
#include "terminaldisplay.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <curses.h>
|
||||
#include <term.h>
|
||||
|
||||
using namespace Terminal;
|
||||
|
||||
Display::Display( bool use_environment )
|
||||
: has_ech( true )
|
||||
{
|
||||
if ( use_environment ) {
|
||||
int errret = -2;
|
||||
int ret = setupterm( (char *)0, 1, &errret );
|
||||
|
||||
if ( ret != OK ) {
|
||||
switch ( errret ) {
|
||||
case 1:
|
||||
throw std::string( "Terminal is hardcopy and cannot be used by curses applications." );
|
||||
break;
|
||||
case 0:
|
||||
throw std::string( "Unknown terminal type." );
|
||||
break;
|
||||
case -1:
|
||||
throw std::string( "Terminfo database could not be found." );
|
||||
break;
|
||||
default:
|
||||
throw std::string( "Unknown terminfo error." );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char *val = tigetstr( "ech" );
|
||||
if ( val <= 0 ) {
|
||||
has_ech = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user