diff --git a/rainbowstream/c_image.py b/rainbowstream/c_image.py index b26142d8..a25ef1da 100644 --- a/rainbowstream/c_image.py +++ b/rainbowstream/c_image.py @@ -3,26 +3,34 @@ from os.path import join, dirname, getmtime, exists, expanduser from .config import * from .py3patch import * +from .util import get_terminal_size import ctypes import sys import os - - -def call_c(): - """ - Call the C program for converting RGB to Ansi colors - """ - library = expanduser('~/.image.so') - sauce = join(dirname(__file__), 'image.c') - if not exists(library) or getmtime(sauce) > getmtime(library): - build = "cc -fPIC -shared -o %s %s" % (library, sauce) - os.system(build + " >/dev/null 2>&1") - image_c = ctypes.cdll.LoadLibrary(library) - image_c.init() - return image_c.rgb_to_ansi - -rgb2short = call_c() +import platform + +from rainbowstream_image import rgb_to_ansi + +# def call_c(): +# """ +# Call the C program for converting RGB to Ansi colors +# """ +# if platform.system() == 'Windows': +# pass +# # library = f'{get_python_lib()}\image.cp36-win32.pyd' +# # image_c = ctypes.cdll.LoadLibrary(library) +# else: +# library = expanduser('~/.image.so') +# sauce = join(dirname(__file__), 'image.c') +# if not exists(library) or getmtime(sauce) > getmtime(library): +# build = "cc -fPIC -shared -o %s %s" % (library, sauce) +# os.system(build + " >/dev/null 2>&1") +# image_c = ctypes.cdll.LoadLibrary(library) +# image_c.init() +# return image_c.rgb_to_ansi + +rgb2short = rgb_to_ansi def pixel_print(pixel): @@ -60,7 +68,7 @@ def image_to_display(path, start=None, length=None): """ Display an image """ - rows, columns = os.popen('stty size', 'r').read().split() + rows, columns = get_terminal_size() if not start: start = c['IMAGE_SHIFT'] if not length: diff --git a/rainbowstream/config.py b/rainbowstream/config.py index 5f5b81bd..0615ef24 100644 --- a/rainbowstream/config.py +++ b/rainbowstream/config.py @@ -103,7 +103,7 @@ def set_config(key, value): # Save with open(path, 'w') as out: json.dump(data, out, indent=4) - os.system('chmod 777 ' + path) + os.chmod(path, 0o777) def delete_config(key): @@ -128,7 +128,7 @@ def delete_config(key): # Save with open(path, 'w') as out: json.dump(data, out, indent=4) - os.system('chmod 777 ' + path) + os.chmod(path, 0o777) def reload_config(): diff --git a/rainbowstream/draw.py b/rainbowstream/draw.py index 62254e6c..d74d91a3 100644 --- a/rainbowstream/draw.py +++ b/rainbowstream/draw.py @@ -17,6 +17,7 @@ from .config import * from .py3patch import * from .emoji import * +from .util import get_terminal_size # Draw global variables dg = {} @@ -446,7 +447,7 @@ def print_thread(partner, me_nick, me_name): me_name = cycle_color(me_name) left = ' ' * margin + partner_name + ' ' + partner_nick right = me_name + ' ' + me_screen_name + ' ' * margin - h, w = os.popen('stty size', 'r').read().split() + h, w = get_terminal_size() w = int(w) line = '{}{}{}'.format( left, ' ' * (w - left_size - right_size - 2 * margin), right) @@ -465,7 +466,7 @@ def print_right_message(m): """ Print a message on the right of screen """ - h, w = os.popen('stty size', 'r').read().split() + h, w = get_terminal_size() w = int(w) frame_width = w // 3 - dg['frame_margin'] frame_width = max(c['THREAD_MIN_WIDTH'], frame_width) @@ -530,7 +531,7 @@ def print_left_message(m): """ Print a message on the left of screen """ - h, w = os.popen('stty size', 'r').read().split() + h, w = get_terminal_size() w = int(w) frame_width = w // 3 - dg['frame_margin'] frame_width = max(c['THREAD_MIN_WIDTH'], frame_width) diff --git a/rainbowstream/image.c b/rainbowstream/image.c index e7d7413f..6f405108 100644 --- a/rainbowstream/image.c +++ b/rainbowstream/image.c @@ -3,6 +3,9 @@ * https://github.com/jart/fabulous/blob/master/fabulous/_xterm256.c * I make a slightly change to fit my module here */ + +#include + typedef struct { int r; int g; @@ -18,6 +21,7 @@ rgb_t BASIC16[] = { 255, 255, 255 } }; rgb_t COLOR_TABLE[256]; +/* __declspec(dllexport) */ rgb_t ansi_to_rgb(int xcolor) { @@ -35,6 +39,32 @@ rgb_t ansi_to_rgb(int xcolor) return res; } +// int rgb_to_ansi(int r, int g, int b) +PyObject * +rgb_to_ansi(PyObject *self, PyObject *args) +{ + int r, g, b; + + if (!PyArg_ParseTuple(args, "iii", &r, &g, &b)) { + return NULL; + } + + int best_match = 0; + int smallest_distance = 1000000000; + int c, d; + for (c = 16; c < 256; c++) { + d = (COLOR_TABLE[c].r - r)*(COLOR_TABLE[c].r - r) + + (COLOR_TABLE[c].g - g)*(COLOR_TABLE[c].g - g) + + (COLOR_TABLE[c].b - b)*(COLOR_TABLE[c].b - b); + if (d < smallest_distance) { + smallest_distance = d; + best_match = c; + } + } + + return Py_BuildValue("i", best_match); +} + int init() { int c; @@ -44,19 +74,31 @@ int init() return 0; } -int rgb_to_ansi(int r, int g, int b) -{ - int best_match = 0; - int smallest_distance = 1000000000; - int c, d; - for (c = 16; c < 256; c++) { - d = (COLOR_TABLE[c].r - r)*(COLOR_TABLE[c].r - r) + - (COLOR_TABLE[c].g - g)*(COLOR_TABLE[c].g - g) + - (COLOR_TABLE[c].b - b)*(COLOR_TABLE[c].b - b); - if (d < smallest_distance) { - smallest_distance = d; - best_match = c; +static PyMethodDef ImageMethods[] = { + {"rgb_to_ansi", (PyCFunction) rgb_to_ansi, METH_VARARGS, "Convert RGB to ANSI"}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +static struct PyModuleDef ImageModule = { + PyModuleDef_HEAD_INIT, + "rainbowstream_image", /* name of module */ + NULL, /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, + or -1 if the module keeps state in global variables. */ + ImageMethods +}; + +PyMODINIT_FUNC +PyInit_rainbowstream_image(void) +{ + PyObject *m; + + m = PyModule_Create(&ImageModule); + if (m == NULL) { + return NULL; } - } - return best_match; + + init(); + + return m; } diff --git a/rainbowstream/interactive.py b/rainbowstream/interactive.py index 76755e8c..44656a0c 100644 --- a/rainbowstream/interactive.py +++ b/rainbowstream/interactive.py @@ -90,7 +90,7 @@ def init_interactive_shell(d): """ readline.set_completer(RainbowCompleter(d).complete) readline.parse_and_bind('set skip-completed-text on') - if 'libedit' in readline.__doc__: + if readline.__doc__ and 'libedit' in readline.__doc__: readline.parse_and_bind("bind ^I rl_complete") else: readline.parse_and_bind("tab: complete") diff --git a/rainbowstream/pure_image.py b/rainbowstream/pure_image.py index 8f027bd6..02619758 100644 --- a/rainbowstream/pure_image.py +++ b/rainbowstream/pure_image.py @@ -2,6 +2,7 @@ from functools import partial from .config import * from .py3patch import * +from .util import get_terminal_size import sys import os @@ -339,7 +340,7 @@ def image_to_display(path, start=None, length=None): """ Display an image """ - rows, columns = os.popen('stty size', 'r').read().split() + rows, columns = get_terminal_size() if not start: start = IMAGE_SHIFT if not length: diff --git a/rainbowstream/rainbow.py b/rainbowstream/rainbow.py index aded31d4..22329a73 100644 --- a/rainbowstream/rainbow.py +++ b/rainbowstream/rainbow.py @@ -1761,7 +1761,7 @@ def help(): Help """ s = ' ' * 2 - h, w = os.popen('stty size', 'r').read().split() + h, w = get_terminal_size() # Start usage = '\n' usage += s + 'Hi boss! I\'m ready to serve you right now!\n' diff --git a/rainbowstream/util.py b/rainbowstream/util.py index a1a2a446..3eba0b98 100644 --- a/rainbowstream/util.py +++ b/rainbowstream/util.py @@ -1,4 +1,7 @@ import json +import shutil +import platform +import os from twitter.util import printNicely from .colors import * @@ -49,6 +52,13 @@ def format_prefix(listname='', keyword=''): return formattedPrefix +def get_terminal_size(): + if platform.system() == 'Windows': + return shutil.get_terminal_size() + else: + return os.popen('stty size', 'r').read().split() + + def add_tweetmode_parameter(kwargs): """ Add support for extended mode to Twitter API calls unless explicitly stated in config diff --git a/setup.py b/setup.py index 872dce18..b487b295 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,14 @@ -from setuptools import setup, find_packages +# from setuptools import setup, find_packages +from distutils.core import setup, Extension +from setuptools import find_packages import os import os.path import sys +import platform +from shutil import copy, chown +import getpass + +image_ext = Extension('rainbowstream_image', sources=['rainbowstream/image.c']) if sys.version[0] == "2": from pipes import quote @@ -20,22 +27,20 @@ "twitter", "Pillow", "PySocks", - "pocket" + "pocket", + "pyreadline" ] # Default user (considers non virtualenv method) -user = os.environ.get('SUDO_USER', os.environ.get('USER', None)) +user = os.environ.get('SUDO_USER', os.environ.get('USER', getpass.getuser())) # Copy default config if not exists default = os.path.expanduser("~") + os.sep + '.rainbow_config.json' if not os.path.isfile(default): - cmd = 'cp rainbowstream/colorset/config ' + default - os.system(cmd) - if user: - cmd = 'chown ' + quote(user) + ' ' + default - os.system(cmd) - cmd = 'chmod 777 ' + default - os.system(cmd) + copy('rainbowstream/colorset/config', default) + if platform.system() != 'Windows' and user: + chown(default, quote(user)) + os.chmod(default, 0o777) # Setup setup(name='rainbowstream', @@ -66,6 +71,7 @@ include_package_data=True, zip_safe=True, install_requires=install_requires, + ext_modules=[image_ext], entry_points=""" # -*- Entry points: -*- [console_scripts]