Fix cursor blur. Fix scrollLock on focus/blur. Rework binaries.

This commit is contained in:
Florian Mounier
2015-10-16 15:58:32 +02:00
parent e6f618ef52
commit 4e4d54de1f
28 changed files with 267 additions and 47 deletions

View File

@@ -22,6 +22,7 @@ import tornado.ioloop
import tornado.httpserver
import tornado_systemd
import logging
import webbrowser
import uuid
import ssl
import getpass
@@ -39,6 +40,8 @@ tornado.options.define("unminified", default=False,
tornado.options.define("host", default='localhost', help="Server host")
tornado.options.define("port", default=57575, type=int, help="Server port")
tornado.options.define("one_shot", default=False,
help="Run a one-shot instance. Quit at term close")
tornado.options.define("shell", help="Shell to execute at login")
tornado.options.define("motd", default='motd', help="Path to the motd file.")
tornado.options.define("cmd",
@@ -66,7 +69,9 @@ if os.getuid() == 0:
ev = os.getenv('XDG_CONFIG_DIRS', '/etc')
else:
ev = os.getenv(
'XDG_CONFIG_HOME', os.path.join(os.getenv('HOME'), '.config'))
'XDG_CONFIG_HOME', os.path.join(
os.getenv('HOME', os.path.expanduser('~')),
'.config'))
butterfly_dir = os.path.join(ev, 'butterfly')
conf_file = os.path.join(butterfly_dir, 'butterfly.conf')
@@ -115,6 +120,7 @@ log = logging.getLogger('butterfly')
host = options.host
port = options.port
if not os.path.exists(options.ssl_dir):
os.makedirs(options.ssl_dir)
@@ -301,7 +307,13 @@ log.info('Starting loop')
ioloop = tornado.ioloop.IOLoop.instance()
if port == 0:
port = list(http_server._sockets.values())[0].getsockname()[1]
url = "http%s://%s:%d/" % (
"s" if not options.unsecure else "", host, port)
log.warn('Butterfly is ready, open your browser to: %s' % url)
if not options.one_shot or not webbrowser.open(url):
log.warn('Butterfly is ready, open your browser to: %s' % url)
ioloop.start()

View File

@@ -14,7 +14,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
__version__ = '2.0.12'
__version__ = '2.0.13'
import os

View File

@@ -1,8 +0,0 @@
#!/usr/bin/env python
import sys
import os
rows, cols = map(int, os.popen('stty size', 'r').read().split())
for r in range(rows):
for c in range(cols):
sys.stdout.write('\x1b[48;2;%d;%d;%dm ' % (255 - r, 255 - c, 255))

0
butterfly/bin/bcal → butterfly/bin/calendar.py Executable file → Normal file
View File

0
butterfly/bin/bcat → butterfly/bin/cat.py Executable file → Normal file
View File

145
butterfly/bin/colors.py Normal file
View File

@@ -0,0 +1,145 @@
#!/usr/bin/env python
import argparse
import sys
parser = argparse.ArgumentParser(description='Butterfly terminal color tester.')
parser.add_argument(
'--colors',
default='16',
choices=['8', '16', '256', '16M'],
help='Set the color mode to test')
args = parser.parse_args()
print()
if args.colors in ['8', '16']:
print('Background\n')
for l in range(3):
sys.stdout.write(' ')
for i in range(8):
sys.stdout.write('\x1b[%dm \x1b[m ' % (40 + i))
sys.stdout.write('\n')
sys.stdout.flush()
if args.colors == '16':
print()
for l in range(3):
sys.stdout.write(' ')
for i in range(8):
sys.stdout.write('\x1b[%dm \x1b[m ' % (100 + i))
sys.stdout.write('\n')
sys.stdout.flush()
print('\nForeground\n')
for l in range(3):
sys.stdout.write(' ')
for i in range(8):
sys.stdout.write('\x1b[%dm ░▒▓██\x1b[m ' % (30 + i))
sys.stdout.write('\n')
sys.stdout.flush()
if args.colors == '16':
print()
for l in range(3):
sys.stdout.write(' ')
for i in range(8):
sys.stdout.write('\x1b[1;%dm ░▒▓██\x1b[m ' % (30 + i))
sys.stdout.write('\n')
sys.stdout.flush()
if args.colors == '256':
for i in range(16):
sys.stdout.write('\x1b[48;5;%dm \x1b[m' % (i))
print()
for i in range(16):
sys.stdout.write('\x1b[48;5;%dm %03d\x1b[m' % (i, i))
print()
for j in range(6):
for i in range(36):
sys.stdout.write('\x1b[48;5;%dm \x1b[m' % (16 + j * 36 + i))
print()
for i in range(36):
sys.stdout.write('\x1b[48;5;%dm %03d\x1b[m' % (
16 + j * 36 + i, 16 + j * 36 + i))
print()
for i in range(24):
sys.stdout.write('\x1b[48;5;%dm \x1b[m' % (232 + i))
print()
for i in range(24):
sys.stdout.write('\x1b[48;5;%dm %03d\x1b[m' % (232 + i, 232 + i))
if args.colors == '16M':
b = 0
g = 0
for r in range(256):
if r == 128:
print()
sys.stdout.write('\x1b[48;2;%d;%d;%dm \x1b[m' % (r, g, b))
print()
r = 255
b = 0
for g in range(256):
if g == 128:
print()
sys.stdout.write('\x1b[48;2;%d;%d;%dm \x1b[m' % (r, g, b))
print()
r = 255
g = 255
for b in range(256):
if b == 128:
print()
sys.stdout.write('\x1b[48;2;%d;%d;%dm \x1b[m' % (r, g, b))
print()
r = 255
b = 255
for g in reversed(range(256)):
if g == 127:
print()
sys.stdout.write('\x1b[48;2;%d;%d;%dm \x1b[m' % (r, g, b))
print()
g = 0
b = 255
for r in reversed(range(256)):
if r == 127:
print()
sys.stdout.write('\x1b[48;2;%d;%d;%dm \x1b[m' % (r, g, b))
print()
r = 0
g = 0
for b in reversed(range(256)):
if b == 127:
print()
sys.stdout.write('\x1b[48;2;%d;%d;%dm \x1b[m' % (r, g, b))
print()
r = 0
b = 0
for g in range(256):
if g == 128:
print()
sys.stdout.write('\x1b[48;2;%d;%d;%dm \x1b[m' % (r, g, b))
print()
r = 0
g = 255
for b in range(256):
if b == 128:
print()
sys.stdout.write('\x1b[48;2;%d;%d;%dm \x1b[m' % (r, g, b))
print()
b = 255
g = 255
for r in range(256):
if r == 128:
print()
sys.stdout.write('\x1b[48;2;%d;%d;%dm \x1b[m' % (r, g, b))
print()

27
butterfly/bin/butterfly_help → butterfly/bin/help.py Executable file → Normal file
View File

@@ -6,12 +6,14 @@ import base64
import shutil
print(ansi_colors.white + "Welcome to the butterfly help." + ansi_colors.reset)
with image('image/png'):
with open(
os.path.join(
os.path.abspath(os.path.dirname(__file__)),
'../static/images/favicon.png'), 'rb') as i:
print(base64.b64encode(i.read()).decode('ascii'))
path = os.getenv('BUTTERFLY_PATH')
if path:
path = os.path.join(path, '../static/images/favicon.png')
if path and os.path.exists(path):
with image('image/png'):
with open(path, 'rb') as i:
print(base64.b64encode(i.read()).decode('ascii'))
print("""
Butterfly is a xterm compliant terminal built with python and javascript.
@@ -28,12 +30,13 @@ Butterfly is a xterm compliant terminal built with python and javascript.
{title}Butterfly programs:{reset}
{strong}bcat : {reset}A wrapper around cat allowing to display images as <img> instead of binary.
{strong}bopen : {reset}Open a new terminal at specified location.
{strong}bsession : {reset}Open or rattach a butterfly session. Multiplexing is supported.
{strong}b16M : {reset}Test the 16M colors support in terminal.
{strong}bhr : {reset}Put a html hr. This is a test for html output.
{strong}bcal : {reset}Display current month using html. This is also a test for html output.
{strong}b : {reset}Alias for {strong}butterfly{reset} executable. Takes a comand in parameter or launch a butterfly server for one shot use (if outside butterfly).
{strong}b cat : {reset}A wrapper around cat allowing to display images as <img> instead of binary.
{strong}b open : {reset}Open a new terminal at specified location.
{strong}b session : {reset}Open or rattach a butterfly session. Multiplexing is supported.
{strong}b colors : {reset}Test the terminal colors (16, 256 and 16777216 colors)
{strong}b hr : {reset}Put a html hr. This is a test for html output.
{strong}b calendar : {reset}Display current month using html. This is also a test for html output.
{title}Styling butterfly:{reset}

0
butterfly/bin/bhr → butterfly/bin/hr.py Executable file → Normal file
View File

0
butterfly/bin/bhtml → butterfly/bin/html.py Executable file → Normal file
View File

0
butterfly/bin/bopen → butterfly/bin/open.py Executable file → Normal file
View File

0
butterfly/bin/bsession → butterfly/bin/session.py Executable file → Normal file
View File

0
butterfly/bin/btest → butterfly/bin/test.py Executable file → Normal file
View File

View File

@@ -288,10 +288,13 @@ class TermWebSocket(Route, tornado.websocket.WebSocketHandler):
else:
self.log.error(
'Socket with neither session nor terminal %r' % self)
if (self.application.systemd and
not len(TermWebSocket.sockets) and
not sum([len(sessions)
for user, sessions in TermWebSocket.terminals.items()])):
opts = tornado.options.options
if opts.one_shot or (
self.application.systemd and
not len(TermWebSocket.sockets) and
not sum([
len(sessions)
for user, sessions in TermWebSocket.terminals.items()])):
sys.exit(0)

View File

@@ -29,4 +29,4 @@ $weights: (ExtraLight 100) (Light 300) (Regular 400) (Medium 500) (Semibold 600)
body
font-family: $font-family
font-size: $font-size
line-height: 1.2
line-height: $font-line-height

View File

@@ -18,7 +18,6 @@
html, body
margin: 0
padding: 0
line-height: 1.2
background-color: $bg
color: $fg

View File

@@ -54,7 +54,8 @@
color: $bg
background-color: $fg
.blur .cursor.reverse-video
.blur .cursor
border: 1px solid $fg
background: none
.nbsp

View File

@@ -17,6 +17,7 @@
/** Font
$font-family: "SourceCodePro" !default
$font-size: 1em !default
$font-line-height: 1.2 !default
/** Colors */
/* Foreground */

File diff suppressed because one or more lines are too long

View File

@@ -2806,7 +2806,6 @@ body {
html, body {
margin: 0;
padding: 0;
line-height: 1.2;
background-color: #110f13;
color: #f4ead5; }
@@ -2923,7 +2922,8 @@ body {
color: #110f13;
background-color: #f4ead5; }
.blur .cursor.reverse-video {
.blur .cursor {
border: 1px solid #f4ead5;
background: none; }
.inline-html {

View File

@@ -310,16 +310,23 @@
};
Terminal.prototype.focus = function() {
var old_sl;
old_sl = this.scrollLock;
this.scrollLock = true;
if (this.sendFocus) {
this.send('\x1b[I');
}
this.showCursor();
this.body.classList.add('focus');
this.body.classList.remove('blur');
return this.resize();
this.resize();
return this.scrollLock = old_sl;
};
Terminal.prototype.blur = function() {
var old_sl;
old_sl = this.scrollLock;
this.scrollLock = true;
this.cursorState = 1;
this.screen[this.y + this.shift].dirty = true;
this.refresh();
@@ -327,7 +334,8 @@
this.send('\x1b[O');
}
this.body.classList.add('blur');
return this.body.classList.remove('focus');
this.body.classList.remove('focus');
return this.scrollLock = old_sl;
};
Terminal.prototype.initmouse = function() {
@@ -698,9 +706,7 @@
}
this.children = Array.prototype.slice.call(lines, -this.rows);
}
if (!this.scrollLock) {
return this.nativeScrollTo();
}
return this.nativeScrollTo();
};
Terminal.prototype._cursorBlink = function() {
@@ -776,6 +782,9 @@
if (scroll == null) {
scroll = 2000000000;
}
if (this.scrollLock) {
return;
}
return window.scrollTo(0, scroll);
};

File diff suppressed because one or more lines are too long

View File

@@ -18,5 +18,5 @@
{{ colors.white }} Y Y {{ colors.light_white }}From:{{ colors.white }}
! ! {{ colors.red if opts.unsecure else colors.green }}{{ butterfly.socket.remote_addr }}:{{ butterfly.socket.remote_port }}{{ colors.reset }}
For more information type: $ butterfly_help
For more information type: {{ colors.white }}$ {{ colors.green }}butterfly help

View File

@@ -159,8 +159,8 @@ class Terminal(object):
env["LOCATION"] = "http%s://%s:%d/" % (
"s" if not tornado.options.options.unsecure else "",
tornado.options.options.host, tornado.options.options.port)
env["PATH"] = '%s:%s' % (os.path.abspath(os.path.join(
os.path.dirname(__file__), 'bin')), env.get("PATH"))
env['BUTTERFLY_PATH'] = os.path.abspath(os.path.join(
os.path.dirname(__file__), 'bin'))
try:
tty = os.ttyname(0).replace('/dev/', '')

View File

@@ -197,13 +197,21 @@ class Terminal
erased
focus: ->
old_sl = @scrollLock
@scrollLock = true
@send('\x1b[I') if @sendFocus
@showCursor()
@body.classList.add('focus')
@body.classList.remove('blur')
@resize()
@scrollLock = old_sl
blur: ->
old_sl = @scrollLock
@scrollLock = true
@cursorState = 1
@screen[@y + @shift].dirty = true
@refresh()
@@ -211,6 +219,8 @@ class Terminal
@body.classList.add('blur')
@body.classList.remove('focus')
@scrollLock = old_sl
# XTerm mouse events
# http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
# To better understand these
@@ -538,7 +548,7 @@ class Terminal
@children = Array.prototype.slice.call(
lines, -@rows)
@nativeScrollTo() unless @scrollLock
@nativeScrollTo()
_cursorBlink: ->
@cursorState ^= 1
@@ -591,6 +601,7 @@ class Terminal
nativeScrollTo: (scroll=2000000000) -> # ~ Max ff number
return if @scrollLock
window.scrollTo 0, scroll
scrollDisplay: (disp) ->

1
scripts/b Symbolic link
View File

@@ -0,0 +1 @@
butterfly

43
scripts/butterfly Executable file
View File

@@ -0,0 +1,43 @@
#!/usr/bin/env python
import os
import sys
import argparse
if (os.getenv('COLORTERM', '') != 'butterfly' and
len(sys.argv) == 1) or (
os.getenv('COLORTERM', '') == 'butterfly' and
len(sys.argv) > 1 and sys.argv[1] == 'run'):
os.execvp('butterfly.server.py', [
'butterfly', '--unsecure', '--port=0', '--one-shot'])
path = os.getenv('BUTTERFLY_PATH')
if not path:
try:
import butterfly
path = os.path.join(
os.path.dirname(butterfly.__file__), 'bin')
except Exception:
pass
os.putenv('BUTTERFLY_PATH', path)
if path is None:
print("Can't get butterfly path. Aborting.")
sys.exit(1)
parser = argparse.ArgumentParser(
add_help=False,
description='Butterfly launcher. Please specify a command')
parser.add_argument('-h', '--help', action="store_true",
help="show this help message and exit")
parser.add_argument(
'command',
nargs='?',
choices=[x[:-3] for x in os.listdir(path) if x.endswith('.py')])
args, _ = parser.parse_known_args()
if not args.command:
parser.print_help()
else:
file_ = os.path.join(path, '%s.py' % args.command)
sys.argv = sys.argv[1:]
exec(compile(open(file_).read(), file_, 'exec'))

View File

@@ -22,7 +22,7 @@ options = dict(
url="http://github.com/paradoxxxzero/butterfly",
license="GPLv3",
platforms="Any",
scripts=['butterfly.server.py'],
scripts=['butterfly.server.py', 'scripts/butterfly', 'scripts/b'],
packages=['butterfly'],
install_requires=["tornado>=3.2", "pyOpenSSL", 'tornado_systemd'],
extras_requires=["libsass"],