mirror of
https://github.com/paradoxxxzero/butterfly.git
synced 2026-05-26 07:08:08 +00:00
Fix cursor blur. Fix scrollLock on focus/blur. Rework binaries.
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
0
butterfly/bin/bcal → butterfly/bin/calendar.py
Executable file → Normal file
0
butterfly/bin/bcat → butterfly/bin/cat.py
Executable file → Normal file
0
butterfly/bin/bcat → butterfly/bin/cat.py
Executable file → Normal file
145
butterfly/bin/colors.py
Normal file
145
butterfly/bin/colors.py
Normal 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
27
butterfly/bin/butterfly_help → butterfly/bin/help.py
Executable file → Normal 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
0
butterfly/bin/bhr → butterfly/bin/hr.py
Executable file → Normal file
0
butterfly/bin/bhtml → butterfly/bin/html.py
Executable file → Normal file
0
butterfly/bin/bhtml → butterfly/bin/html.py
Executable file → Normal file
0
butterfly/bin/bopen → butterfly/bin/open.py
Executable file → Normal file
0
butterfly/bin/bopen → butterfly/bin/open.py
Executable file → Normal file
0
butterfly/bin/bsession → butterfly/bin/session.py
Executable file → Normal file
0
butterfly/bin/bsession → butterfly/bin/session.py
Executable file → Normal file
0
butterfly/bin/btest → butterfly/bin/test.py
Executable file → Normal file
0
butterfly/bin/btest → butterfly/bin/test.py
Executable file → Normal 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)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
html, body
|
||||
margin: 0
|
||||
padding: 0
|
||||
line-height: 1.2
|
||||
background-color: $bg
|
||||
color: $fg
|
||||
|
||||
|
||||
@@ -54,7 +54,8 @@
|
||||
color: $bg
|
||||
background-color: $fg
|
||||
|
||||
.blur .cursor.reverse-video
|
||||
.blur .cursor
|
||||
border: 1px solid $fg
|
||||
background: none
|
||||
|
||||
.nbsp
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
/** Font
|
||||
$font-family: "SourceCodePro" !default
|
||||
$font-size: 1em !default
|
||||
$font-line-height: 1.2 !default
|
||||
|
||||
/** Colors */
|
||||
/* Foreground */
|
||||
|
||||
2
butterfly/static/ext.min.js
vendored
2
butterfly/static/ext.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
6
butterfly/static/main.min.js
vendored
6
butterfly/static/main.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -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
|
||||
|
||||
|
||||
@@ -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/', '')
|
||||
|
||||
Submodule butterfly/themes updated: c9dd55f4e6...cfad944d6f
@@ -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) ->
|
||||
|
||||
43
scripts/butterfly
Executable file
43
scripts/butterfly
Executable 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'))
|
||||
2
setup.py
2
setup.py
@@ -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"],
|
||||
|
||||
Reference in New Issue
Block a user