mirror of
https://github.com/paradoxxxzero/butterfly.git
synced 2026-05-26 15:13:36 +00:00
Add theme and session support bin.
This commit is contained in:
13
butterfly/bin/bsession
Executable file
13
butterfly/bin/bsession
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
import webbrowser
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Butterfly session opener.')
|
||||
parser.add_argument(
|
||||
'session',
|
||||
help='Open or rattach a butterfly session. '
|
||||
'(Only in secure mode or in user unsecure mode (no su login))')
|
||||
args = parser.parse_args()
|
||||
|
||||
webbrowser.open('%ssession/%s' % (os.getenv('LOCATION'), args.session))
|
||||
87
butterfly/bin/btheme
Executable file
87
butterfly/bin/btheme
Executable file
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
except ImportError:
|
||||
from urllib import urlopen
|
||||
|
||||
from io import BytesIO
|
||||
from shutil import move
|
||||
from zipfile import ZipFile
|
||||
from tempfile import mkdtemp
|
||||
from butterfly.escapes import sass
|
||||
|
||||
try:
|
||||
import sass as _
|
||||
_.CompileError
|
||||
except Exception:
|
||||
print('You must install libsass to use themes '
|
||||
'(run: pip install libsass)')
|
||||
sys.exit(1)
|
||||
|
||||
themes_url = ("https://github.com/paradoxxxzero/"
|
||||
"butterfly-themes/archive/master.zip")
|
||||
|
||||
parser = argparse.ArgumentParser(description='Butterfly session opener.')
|
||||
parser.add_argument(
|
||||
'--install',
|
||||
action="store_true",
|
||||
help='Install preset themes from '
|
||||
'https://github.com/paradoxxxzero/butterfly-themes')
|
||||
|
||||
parser.add_argument(
|
||||
'--refresh',
|
||||
action="store_true",
|
||||
help='Refresh the current style')
|
||||
|
||||
parser.add_argument(
|
||||
'-g',
|
||||
action="store_true",
|
||||
help='Install system wide for usage with butterfly as daemon')
|
||||
|
||||
parser.add_argument(
|
||||
'theme',
|
||||
nargs='?',
|
||||
help='Theme to load. '
|
||||
'Can be a sass file or a directory containing a sass file.')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.g:
|
||||
home_dir = os.path.join('/etc', 'butterfly')
|
||||
else:
|
||||
home_dir = os.path.expanduser(os.path.join('~', '.butterfly'))
|
||||
|
||||
if args.install:
|
||||
print('Downloading %s...' % themes_url)
|
||||
zip_ = ZipFile(BytesIO(urlopen(themes_url).read()))
|
||||
|
||||
print('Extracting in %s' % home_dir)
|
||||
zip_.extractall(home_dir)
|
||||
|
||||
zip_dest = os.path.join(home_dir, 'butterfly-themes-master')
|
||||
theme_dir = os.path.join(home_dir, 'themes')
|
||||
if os.path.exists(theme_dir):
|
||||
tmp_dir = mkdtemp()
|
||||
print('%s already present. Putting it in %s.' % (
|
||||
theme_dir, os.path.join(tmp_dir, 'themes')))
|
||||
move(theme_dir, tmp_dir)
|
||||
move(zip_dest, theme_dir)
|
||||
print('%s extracted.' % theme_dir)
|
||||
|
||||
elif args.refresh:
|
||||
with sass():
|
||||
pass
|
||||
|
||||
else:
|
||||
sss = os.path.abspath(args.theme or home_dir)
|
||||
if not os.path.exists(sss):
|
||||
sss = os.path.join(home_dir, 'themes', args.theme)
|
||||
if not os.path.exists(sss):
|
||||
print('%s not found' % sss)
|
||||
sys.exit(1)
|
||||
|
||||
print('Loading %s' % sss)
|
||||
with sass():
|
||||
sys.stdout.write(sss)
|
||||
@@ -23,24 +23,33 @@ 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}b16M : {reset}Test the 16M colors support in terminal.
|
||||
{strong}bhr : {reset}Put a html hr. This is a test and needs --allow-html-escapes flag.
|
||||
{strong}bcal : {reset}Display current month using html. This is a test and needs --allow-html-escapes flag.
|
||||
{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}bopen : {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}btheme : {reset}Set a theme as current theme. (Can also install preset themes)
|
||||
|
||||
|
||||
{title}Styling butterfly:{reset}
|
||||
To style butterfly in sass, you need to have the libsass python library installed.
|
||||
|
||||
You will have to:
|
||||
$ cp {main} ~/.butterfly/style.sass
|
||||
or for system wide:
|
||||
# cp {main} /etc/butterfly/style.sass
|
||||
First check out existing themes, run:
|
||||
$ btheme --install
|
||||
Then try:
|
||||
$ btheme solarized-dark # or C64 or abstract-image
|
||||
If you want to set a theme as default add a 'style=theme' line in your butterfly.conf
|
||||
|
||||
If you want to style it yourself do:
|
||||
$ cp {main} ~/.butterfly/style.sass # or /etc/butterfly/style.sass for system wide
|
||||
and then edit this file.
|
||||
|
||||
You can also copy the imported sass files in the same dir.
|
||||
Sass files are compiled on the fly so just reload your tab to see the changes.
|
||||
You can also copy the imported sass files in the same dir. Run:
|
||||
$ btheme --refresh
|
||||
To update the style in the current terminal.
|
||||
|
||||
Finally when your theme is done please submit it to https://github.com/paradoxxxzero/butterfly-themes
|
||||
|
||||
It is also possible to use a style.css file and re do all the styling in css exclusively.\
|
||||
""".format(
|
||||
|
||||
@@ -32,3 +32,11 @@ def text():
|
||||
yield
|
||||
sys.stdout.write('\x1bP')
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
@contextmanager
|
||||
def sass():
|
||||
sys.stdout.write('\x1bP;SASS|')
|
||||
yield
|
||||
sys.stdout.write('\x1bP')
|
||||
sys.stdout.flush()
|
||||
|
||||
@@ -22,6 +22,7 @@ import tornado.options
|
||||
import tornado.process
|
||||
import tornado.web
|
||||
import tornado.websocket
|
||||
from mimetypes import guess_type
|
||||
from collections import defaultdict
|
||||
from butterfly import url, Route, utils, __version__
|
||||
from butterfly.terminal import Terminal
|
||||
@@ -68,28 +69,44 @@ class Style(Route):
|
||||
|
||||
|
||||
@url(r'/theme/font/([^/]+)')
|
||||
class Font(Route):
|
||||
class ThemeFont(Route):
|
||||
|
||||
def get(self, name):
|
||||
if not tornado.options.options.theme or not name:
|
||||
raise tornado.web.HTTPError(404)
|
||||
font = 'themes/%s/font/%s' % (
|
||||
tornado.options.options.theme,
|
||||
name)
|
||||
for fn in [
|
||||
'/etc/butterfly/%s' % font,
|
||||
os.path.expanduser('~/.butterfly/%s' % font)]:
|
||||
if os.path.exists(fn):
|
||||
ext = fn.split('.')[-1]
|
||||
self.set_header("Content-Type", "application/x-font-%s" % ext)
|
||||
with open(fn, 'rb') as s:
|
||||
while True:
|
||||
data = s.read(16384)
|
||||
if data:
|
||||
self.write(data)
|
||||
else:
|
||||
break
|
||||
self.finish()
|
||||
fn = os.path.join(
|
||||
os.path.dirname(utils.get_style_path()), 'font', name)
|
||||
if os.path.exists(fn):
|
||||
self.set_header("Content-Type", guess_type(fn)[0])
|
||||
with open(fn, 'rb') as s:
|
||||
while True:
|
||||
data = s.read(16384)
|
||||
if data:
|
||||
self.write(data)
|
||||
else:
|
||||
break
|
||||
self.finish()
|
||||
raise tornado.web.HTTPError(404)
|
||||
|
||||
|
||||
@url(r'/theme/image/([^/]+)')
|
||||
class ThemeImage(Route):
|
||||
|
||||
def get(self, name):
|
||||
if not tornado.options.options.theme or not name:
|
||||
raise tornado.web.HTTPError(404)
|
||||
fn = os.path.join(
|
||||
os.path.dirname(utils.get_style_path()), 'image', name)
|
||||
if os.path.exists(fn):
|
||||
self.set_header("Content-Type", guess_type(fn)[0])
|
||||
with open(fn, 'rb') as s:
|
||||
while True:
|
||||
data = s.read(16384)
|
||||
if data:
|
||||
self.write(data)
|
||||
else:
|
||||
break
|
||||
self.finish()
|
||||
raise tornado.web.HTTPError(404)
|
||||
|
||||
|
||||
|
||||
@@ -18,22 +18,35 @@
|
||||
|
||||
/* Here are the 16 "normal" colors for theming */
|
||||
|
||||
+termcolor(0, #2e3436) /* Black */
|
||||
+termcolor(1, #cc0000) /* Red */
|
||||
+termcolor(2, #4e9a06) /* Green */
|
||||
+termcolor(3, #c4a000) /* Yellow */
|
||||
+termcolor(4, #3465a4) /* Blue */
|
||||
+termcolor(5, #75507b) /* Magenta */
|
||||
+termcolor(6, #06989a) /* Cyan */
|
||||
+termcolor(7, #d3d7cf) /* White */
|
||||
+termcolor(8, #555753) /* Bright Black */
|
||||
+termcolor(9, #ef2929) /* Bright Red */
|
||||
+termcolor(10, #8ae234) /* Bright Green */
|
||||
+termcolor(11, #fce94f) /* Bright Yellow */
|
||||
+termcolor(12, #729fcf) /* Bright Blue */
|
||||
+termcolor(13, #ad7fa8) /* Bright Magenta */
|
||||
+termcolor(14, #34e2e2) /* Bright Cyan */
|
||||
+termcolor(15, #eeeeec) /* Bright White */
|
||||
|
||||
$bg: #110f13
|
||||
$fg: #f4ead5
|
||||
/* Black */
|
||||
+termcolor(0, #2e3436)
|
||||
/* Red */
|
||||
+termcolor(1, #cc0000)
|
||||
/* Green */
|
||||
+termcolor(2, #4e9a06)
|
||||
/* Yellow */
|
||||
+termcolor(3, #c4a000)
|
||||
/* Blue */
|
||||
+termcolor(4, #3465a4)
|
||||
/* Magenta */
|
||||
+termcolor(5, #75507b)
|
||||
/* Cyan */
|
||||
+termcolor(6, #06989a)
|
||||
/* White */
|
||||
+termcolor(7, #d3d7cf)
|
||||
/* Bright Black */
|
||||
+termcolor(8, #555753)
|
||||
/* Bright Red */
|
||||
+termcolor(9, #ef2929)
|
||||
/* Bright Green */
|
||||
+termcolor(10, #8ae234)
|
||||
/* Bright Yellow */
|
||||
+termcolor(11, #fce94f)
|
||||
/* Bright Blue */
|
||||
+termcolor(12, #729fcf)
|
||||
/* Bright Magenta */
|
||||
+termcolor(13, #ad7fa8)
|
||||
/* Bright Cyan */
|
||||
+termcolor(14, #34e2e2)
|
||||
/* Bright White */
|
||||
+termcolor(15, #eeeeec)
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
/* You should have received a copy of the GNU General Public License */
|
||||
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
$fg: #fff !default
|
||||
$bg: #000 !default
|
||||
$fg: #f4ead5 !default
|
||||
$bg: #110f13 !default
|
||||
|
||||
/* Here are the 240 xterm colors */
|
||||
/* See http://upload.wikimedia.org/wikipedia/en/1/15/Xterm_256color_chart.svg */
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
/* You should have received a copy of the GNU General Public License */
|
||||
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
$fg: #fff !default
|
||||
$bg: #000 !default
|
||||
|
||||
.bold
|
||||
font-weight: bold
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@
|
||||
} else {
|
||||
node = needle.node;
|
||||
}
|
||||
text = node.textContent;
|
||||
text = node != null ? node.textContent : void 0;
|
||||
i = needle.offset;
|
||||
if (backward) {
|
||||
while (node) {
|
||||
@@ -276,7 +276,7 @@
|
||||
}
|
||||
}
|
||||
node = previousLeaf(node);
|
||||
text = node.textContent;
|
||||
text = node != null ? node.textContent : void 0;
|
||||
i = text.length;
|
||||
}
|
||||
} else {
|
||||
@@ -290,7 +290,7 @@
|
||||
}
|
||||
}
|
||||
node = nextLeaf(node);
|
||||
text = node.textContent;
|
||||
text = node != null ? node.textContent : void 0;
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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
@@ -156,6 +156,7 @@ body {
|
||||
/* You should have received a copy of the GNU General Public License */
|
||||
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Here are the 16 "normal" colors for theming */
|
||||
/* Black */
|
||||
.bg-color-0 {
|
||||
background-color: #2e3436; }
|
||||
.bg-color-0.reverse-video {
|
||||
@@ -167,7 +168,7 @@ body {
|
||||
.fg-color-0.reverse-video {
|
||||
background-color: #2e3436 !important; }
|
||||
|
||||
/* Black */
|
||||
/* Red */
|
||||
.bg-color-1 {
|
||||
background-color: #cc0000; }
|
||||
.bg-color-1.reverse-video {
|
||||
@@ -179,7 +180,7 @@ body {
|
||||
.fg-color-1.reverse-video, .reverse-video.nbsp {
|
||||
background-color: #cc0000 !important; }
|
||||
|
||||
/* Red */
|
||||
/* Green */
|
||||
.bg-color-2 {
|
||||
background-color: #4e9a06; }
|
||||
.bg-color-2.reverse-video {
|
||||
@@ -191,7 +192,7 @@ body {
|
||||
.fg-color-2.reverse-video {
|
||||
background-color: #4e9a06 !important; }
|
||||
|
||||
/* Green */
|
||||
/* Yellow */
|
||||
.bg-color-3 {
|
||||
background-color: #c4a000; }
|
||||
.bg-color-3.reverse-video {
|
||||
@@ -203,7 +204,7 @@ body {
|
||||
.fg-color-3.reverse-video {
|
||||
background-color: #c4a000 !important; }
|
||||
|
||||
/* Yellow */
|
||||
/* Blue */
|
||||
.bg-color-4 {
|
||||
background-color: #3465a4; }
|
||||
.bg-color-4.reverse-video {
|
||||
@@ -215,7 +216,7 @@ body {
|
||||
.fg-color-4.reverse-video {
|
||||
background-color: #3465a4 !important; }
|
||||
|
||||
/* Blue */
|
||||
/* Magenta */
|
||||
.bg-color-5 {
|
||||
background-color: #75507b; }
|
||||
.bg-color-5.reverse-video {
|
||||
@@ -227,7 +228,7 @@ body {
|
||||
.fg-color-5.reverse-video {
|
||||
background-color: #75507b !important; }
|
||||
|
||||
/* Magenta */
|
||||
/* Cyan */
|
||||
.bg-color-6 {
|
||||
background-color: #06989a; }
|
||||
.bg-color-6.reverse-video {
|
||||
@@ -239,7 +240,7 @@ body {
|
||||
.fg-color-6.reverse-video {
|
||||
background-color: #06989a !important; }
|
||||
|
||||
/* Cyan */
|
||||
/* White */
|
||||
.bg-color-7 {
|
||||
background-color: #d3d7cf; }
|
||||
.bg-color-7.reverse-video {
|
||||
@@ -251,7 +252,7 @@ body {
|
||||
.fg-color-7.reverse-video {
|
||||
background-color: #d3d7cf !important; }
|
||||
|
||||
/* White */
|
||||
/* Bright Black */
|
||||
.bg-color-8 {
|
||||
background-color: #555753; }
|
||||
.bg-color-8.reverse-video {
|
||||
@@ -263,7 +264,7 @@ body {
|
||||
.fg-color-8.reverse-video {
|
||||
background-color: #555753 !important; }
|
||||
|
||||
/* Bright Black */
|
||||
/* Bright Red */
|
||||
.bg-color-9 {
|
||||
background-color: #ef2929; }
|
||||
.bg-color-9.reverse-video {
|
||||
@@ -275,7 +276,7 @@ body {
|
||||
.fg-color-9.reverse-video {
|
||||
background-color: #ef2929 !important; }
|
||||
|
||||
/* Bright Red */
|
||||
/* Bright Green */
|
||||
.bg-color-10 {
|
||||
background-color: #8ae234; }
|
||||
.bg-color-10.reverse-video {
|
||||
@@ -287,7 +288,7 @@ body {
|
||||
.fg-color-10.reverse-video {
|
||||
background-color: #8ae234 !important; }
|
||||
|
||||
/* Bright Green */
|
||||
/* Bright Yellow */
|
||||
.bg-color-11 {
|
||||
background-color: #fce94f; }
|
||||
.bg-color-11.reverse-video {
|
||||
@@ -299,7 +300,7 @@ body {
|
||||
.fg-color-11.reverse-video {
|
||||
background-color: #fce94f !important; }
|
||||
|
||||
/* Bright Yellow */
|
||||
/* Bright Blue */
|
||||
.bg-color-12 {
|
||||
background-color: #729fcf; }
|
||||
.bg-color-12.reverse-video {
|
||||
@@ -311,7 +312,7 @@ body {
|
||||
.fg-color-12.reverse-video {
|
||||
background-color: #729fcf !important; }
|
||||
|
||||
/* Bright Blue */
|
||||
/* Bright Magenta */
|
||||
.bg-color-13 {
|
||||
background-color: #ad7fa8; }
|
||||
.bg-color-13.reverse-video {
|
||||
@@ -323,7 +324,7 @@ body {
|
||||
.fg-color-13.reverse-video {
|
||||
background-color: #ad7fa8 !important; }
|
||||
|
||||
/* Bright Magenta */
|
||||
/* Bright Cyan */
|
||||
.bg-color-14 {
|
||||
background-color: #34e2e2; }
|
||||
.bg-color-14.reverse-video {
|
||||
@@ -335,7 +336,7 @@ body {
|
||||
.fg-color-14.reverse-video {
|
||||
background-color: #34e2e2 !important; }
|
||||
|
||||
/* Bright Cyan */
|
||||
/* Bright White */
|
||||
.bg-color-15 {
|
||||
background-color: #eeeeec; }
|
||||
.bg-color-15.reverse-video {
|
||||
@@ -347,7 +348,6 @@ body {
|
||||
.fg-color-15.reverse-video {
|
||||
background-color: #eeeeec !important; }
|
||||
|
||||
/* Bright White */
|
||||
/* *-* coding: utf-8 *-* */
|
||||
/* This file is part of butterfly */
|
||||
/* butterfly Copyright (C) 2014 Florian Mounier */
|
||||
@@ -3015,15 +3015,15 @@ body {
|
||||
background-color: #110f13 !important; }
|
||||
|
||||
.bg-color-257 {
|
||||
background-color: #f4ead5; }
|
||||
background-color: #fff; }
|
||||
.bg-color-257.reverse-video {
|
||||
color: #f4ead5 !important; }
|
||||
color: #fff !important; }
|
||||
|
||||
.fg-color-257 {
|
||||
color: #f4ead5;
|
||||
text-shadow: 0 0 6px rgba(244, 234, 213, 0.5); }
|
||||
color: #fff;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.5); }
|
||||
.fg-color-257.reverse-video {
|
||||
background-color: #f4ead5 !important; }
|
||||
background-color: #fff !important; }
|
||||
|
||||
/* *-* coding: utf-8 *-* */
|
||||
/* This file is part of butterfly */
|
||||
@@ -3043,7 +3043,7 @@ html, body {
|
||||
padding: 0;
|
||||
line-height: 1.2;
|
||||
background-color: #110f13;
|
||||
color: #f4ead5; }
|
||||
color: #fff; }
|
||||
|
||||
body {
|
||||
white-space: nowrap;
|
||||
@@ -3053,9 +3053,9 @@ body {
|
||||
background: #110f13;
|
||||
width: .75em; }
|
||||
body::-webkit-scrollbar-thumb {
|
||||
background: rgba(244, 234, 213, 0.1); }
|
||||
background: rgba(255, 255, 255, 0.1); }
|
||||
body::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(244, 234, 213, 0.15); }
|
||||
background: rgba(255, 255, 255, 0.15); }
|
||||
|
||||
.terminal {
|
||||
outline: none; }
|
||||
@@ -3077,7 +3077,7 @@ body {
|
||||
transition: 300ms; }
|
||||
|
||||
.cursor.reverse-video {
|
||||
box-shadow: 0 0 0.5 #f4ead5; }
|
||||
box-shadow: 0 0 0.5 #fff; }
|
||||
|
||||
/* *-* coding: utf-8 *-* */
|
||||
/* This file is part of butterfly */
|
||||
@@ -3117,7 +3117,7 @@ body {
|
||||
|
||||
.reverse-video {
|
||||
color: #110f13;
|
||||
background-color: #f4ead5; }
|
||||
background-color: #fff; }
|
||||
|
||||
.blur .cursor.reverse-video {
|
||||
background: none; }
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
params = args.join(',');
|
||||
if (type === 'Resize') {
|
||||
return ws.send('R' + params);
|
||||
} else if (type === 'Theme') {
|
||||
return ws.send('T' + params);
|
||||
}
|
||||
};
|
||||
if (location.protocol === 'https:') {
|
||||
@@ -1224,7 +1226,7 @@
|
||||
}
|
||||
pt = pt.slice(1);
|
||||
ref3 = pt.split('|', 2), type = ref3[0], content = ref3[1];
|
||||
if (!content) {
|
||||
if (!content && type !== 'SASS') {
|
||||
console.error("No type for inline DECUDK: " + pt);
|
||||
break;
|
||||
}
|
||||
@@ -1262,6 +1264,12 @@
|
||||
l += content.length;
|
||||
data = data.slice(0, i + 1) + content + data.slice(i + 1);
|
||||
break;
|
||||
case "SASS":
|
||||
if (content.length) {
|
||||
this.ctl('Theme', content);
|
||||
}
|
||||
setTimeout(this.refreshStyle.bind(this), 50);
|
||||
break;
|
||||
default:
|
||||
console.error("Unknown type " + type + " for DECUDK");
|
||||
}
|
||||
@@ -1432,6 +1440,9 @@
|
||||
break;
|
||||
case 33:
|
||||
if (ev.shiftKey) {
|
||||
if (ev.ctrlKey) {
|
||||
break;
|
||||
}
|
||||
this.scrollDisplay(-(this.rows - 1));
|
||||
return cancel(ev);
|
||||
} else {
|
||||
@@ -1440,6 +1451,9 @@
|
||||
break;
|
||||
case 34:
|
||||
if (ev.shiftKey) {
|
||||
if (ev.ctrlKey) {
|
||||
break;
|
||||
}
|
||||
this.scrollDisplay(this.rows - 1);
|
||||
return cancel(ev);
|
||||
} else {
|
||||
@@ -2687,6 +2701,11 @@
|
||||
return results;
|
||||
};
|
||||
|
||||
Terminal.prototype.refreshStyle = function() {
|
||||
document.getElementById('style').setAttribute('href', '/style.css?' + new Date().getTime());
|
||||
return setTimeout(this.resize.bind(this), 300);
|
||||
};
|
||||
|
||||
Terminal.prototype.charsets = {
|
||||
SCLD: {
|
||||
"`": "◆",
|
||||
|
||||
4
butterfly/static/main.min.js
vendored
4
butterfly/static/main.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -10,7 +10,7 @@
|
||||
<link rel="shortcut icon" href="{{ static_url('images/favicon.png') }}">
|
||||
|
||||
<title>Butterfly</title>
|
||||
<link href="/style.css" rel="stylesheet">
|
||||
<link href="/style.css" rel="stylesheet" id="style">
|
||||
</head>
|
||||
|
||||
<body spellcheck="false"
|
||||
|
||||
@@ -278,6 +278,8 @@ class Terminal(object):
|
||||
log.debug('WRIT<%r' % message)
|
||||
self.writer.write(message[1:])
|
||||
self.writer.flush()
|
||||
elif message[0] == 'T':
|
||||
tornado.options.options.theme = message[1:]
|
||||
|
||||
def shell_handler(self, fd, events):
|
||||
if events & ioloop.READ:
|
||||
|
||||
@@ -30,11 +30,19 @@ import re
|
||||
log = getLogger('butterfly')
|
||||
|
||||
|
||||
def get_style():
|
||||
style = None
|
||||
def get_style_path():
|
||||
opts = tornado.options.options
|
||||
|
||||
if tornado.options.options.theme:
|
||||
theme = 'themes/%s/' % tornado.options.options.theme
|
||||
if opts.theme and os.path.exists(opts.theme):
|
||||
if os.path.isdir(opts.theme):
|
||||
theme = os.path.join(opts.theme, 'style.sass')
|
||||
if os.path.exists(theme):
|
||||
return theme
|
||||
else:
|
||||
return opts.theme
|
||||
|
||||
if opts.theme:
|
||||
theme = 'themes/%s/' % opts.theme
|
||||
else:
|
||||
theme = '/'
|
||||
|
||||
@@ -43,8 +51,11 @@ def get_style():
|
||||
'/etc/butterfly/%sstyle' % theme,
|
||||
os.path.expanduser('~/.butterfly/%sstyle' % theme)]:
|
||||
if os.path.exists('%s.%s' % (fn, ext)):
|
||||
style = '%s.%s' % (fn, ext)
|
||||
return '%s.%s' % (fn, ext)
|
||||
|
||||
|
||||
def get_style():
|
||||
style = get_style_path()
|
||||
if style is None:
|
||||
return
|
||||
|
||||
@@ -53,18 +64,19 @@ def get_style():
|
||||
os.path.dirname(__file__), 'sass')
|
||||
try:
|
||||
import sass
|
||||
sass.CompileError
|
||||
except Exception:
|
||||
log.error('You must install libsass to use sass '
|
||||
'(pip install libsass)')
|
||||
return
|
||||
|
||||
base = os.path.dirname(style)
|
||||
try:
|
||||
return sass.compile(filename=style, include_paths=[
|
||||
theme, sass_path])
|
||||
base, sass_path])
|
||||
except sass.CompileError:
|
||||
log.error(
|
||||
'Unable to compile style.scss (filename: %s, paths: %r) ' % (
|
||||
style, [theme, sass_path]), exc_info=True)
|
||||
style, [base, sass_path]), exc_info=True)
|
||||
return
|
||||
|
||||
with open(style) as s:
|
||||
|
||||
@@ -148,7 +148,7 @@ class Selection
|
||||
else
|
||||
node = needle.node
|
||||
|
||||
text = node.textContent
|
||||
text = node?.textContent
|
||||
i = needle.offset
|
||||
if backward
|
||||
while node
|
||||
@@ -156,7 +156,7 @@ class Selection
|
||||
if text[--i].match til
|
||||
return node: node, offset: i + 1
|
||||
node = previousLeaf node
|
||||
text = node.textContent
|
||||
text = node?.textContent
|
||||
i = text.length
|
||||
else
|
||||
while node
|
||||
@@ -164,7 +164,7 @@ class Selection
|
||||
if text[i++].match til
|
||||
return node: node, offset: i - 1
|
||||
node = nextLeaf node
|
||||
text = node.textContent
|
||||
text = node?.textContent
|
||||
i = 0
|
||||
|
||||
return needle
|
||||
|
||||
@@ -30,6 +30,8 @@ document.addEventListener 'DOMContentLoaded', ->
|
||||
params = args.join(',')
|
||||
if type == 'Resize'
|
||||
ws.send 'R' + params
|
||||
else if type == 'Theme'
|
||||
ws.send 'T' + params
|
||||
|
||||
if location.protocol == 'https:'
|
||||
wsUrl = 'wss://'
|
||||
|
||||
@@ -1115,7 +1115,7 @@ class Terminal
|
||||
|
||||
[type, content] = pt.split('|', 2)
|
||||
|
||||
unless content
|
||||
if not content and type isnt 'SASS'
|
||||
console.error "No type for inline DECUDK: #{pt}"
|
||||
break
|
||||
|
||||
@@ -1154,6 +1154,13 @@ class Terminal
|
||||
when "TEXT"
|
||||
l += content.length
|
||||
data = data.slice(0, i + 1) + content + data.slice(i + 1)
|
||||
|
||||
when "SASS"
|
||||
# sass file
|
||||
if content.length
|
||||
@ctl 'Theme', content
|
||||
setTimeout @refreshStyle.bind(@), 50
|
||||
|
||||
else
|
||||
console.error "Unknown type #{type} for DECUDK"
|
||||
|
||||
@@ -1333,6 +1340,7 @@ class Terminal
|
||||
# page up
|
||||
when 33
|
||||
if ev.shiftKey
|
||||
break if ev.ctrlKey
|
||||
@scrollDisplay -(@rows - 1)
|
||||
return cancel(ev)
|
||||
else
|
||||
@@ -1341,6 +1349,7 @@ class Terminal
|
||||
# page down
|
||||
when 34
|
||||
if ev.shiftKey
|
||||
break if ev.ctrlKey
|
||||
@scrollDisplay @rows - 1
|
||||
return cancel(ev)
|
||||
else
|
||||
@@ -3045,6 +3054,12 @@ class Terminal
|
||||
@screen[i].wrap = false
|
||||
i++
|
||||
|
||||
refreshStyle: ->
|
||||
document.getElementById('style').setAttribute(
|
||||
'href', '/style.css?' + new Date().getTime())
|
||||
setTimeout @resize.bind(@), 300
|
||||
|
||||
|
||||
# DEC Special Character and Line Drawing Set.
|
||||
# http://vt100.net/docs/vt102-ug/table5-13.html
|
||||
# A lot of curses apps use this if they see TERM=xterm.
|
||||
|
||||
Reference in New Issue
Block a user