Добавлен объект преобразования консольного текста.

Объекты вывода цветного текста  в терминал256, терминал, span блоки
master3.3
Mike Hiretsky 10 years ago
parent 9c1fb488e4
commit 11cd50c66d

@ -814,7 +814,7 @@ class SimpleDataVars:
"""
Unserialize form string for varname
"""
fixEmpty = lambda x:"" if x=="''" else x
fixEmpty = lambda x:"" if x=="''" or x=='""' else x
def getList(delimeter=','):
def wrapper(val):
if val == "":
@ -825,7 +825,7 @@ class SimpleDataVars:
return getList()(value)
if "table" in varType:
return map(getList(':'),value.split(','))
return fixEmpty(value).strip("'")
return fixEmpty(value).strip("'").strip('"')
class DataVars(SimpleDataVars):

@ -0,0 +1,188 @@
#-*- coding: utf-8 -*-
# Copyright 2014 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from output import BaseOutput
from palette import (TextState, BaseColorMapping, ConsoleCodesInfo,
ConsoleCodeMapping, LightColorMapping, ConsoleColor256)
from calculate.lib.utils.tools import SavableIterator
from itertools import chain,ifilter
import re
class ConsoleCodesConverter(object):
"""Преобразователь текста из цветного консольного вывода через объект
форматирования.
Объект форматирования должен реализовывать BaseOutput
>>> cct = ConsoleCodesConverter(BaseOutput())
>>> outtext = "\033[32;1mHello\033[0;39m"
>>> cct.transform(outtext)
'Hello'
>>> cct = ConsoleCodesConverter(SpanCssOutput())
>>> outtext = "\033[32;1mHello\033[0;39m"
>>> cct.transform(outtext)
'<span style="color:Green;font-weight:bold;">Hello</span>'
"""
class CodeElement:
"""Элемент кода в ESC последовательности"""
def __init__(self,condition=lambda code:False,action=lambda :None):
self.action = action
self.condition = condition
def tryParse(self,code):
"""Обрабатывает ли экземпляр код"""
return self.condition(code)
def parse(self,code,codes):
"""Обработать код, вызвать действие"""
self.action()
def _next_code(self,other):
"""
Получить следующий код
"""
try:
return int(other.next())
except StopIteration:
return None
class ColorElement:
"""Элемент кода для указания стандартного цвета
Проверка кода в интервале, запуск действия с передачей цвета
"""
# соответствие консольных цветов внутренним цветам
mapColors = BaseColorMapping.mapConsole_TS
def __init__(self,action=lambda x:None, begin=None, end=None):
self.action = action
self.begin = begin
self.end = end
def tryParse(self,code):
cci = ConsoleCodesInfo
return code >=self.begin and code <= self.end
def parse(self,code,codes):
cci = ConsoleCodesInfo
return self.action(self.mapColors.get(code-self.begin,
TextState.Colors.DEFAULT))
def __init__(self,output=None,escSymb="\033"):
self.output = output or BaseOutput()
self.escSymb = escSymb
self.reParse = re.compile(
"({0}\[\d+(?:;\d+)*m)?(.*?)(?=$|{0}\[\d)".format(escSymb),
re.DOTALL)
resetBoldHalfbright = lambda : (
(self.output.resetBold() or "") +
(self.output.resetHalfbright() or ""))
cci = ConsoleCodesInfo
element = self.CodeElement
# набор правил обработки кодов
reset = element(lambda code:code==cci.RESET, self.output.reset)
bold = element(lambda code:code==cci.BOLD, self.output.setBold)
halfbright = element(lambda code:code==cci.HALFBRIGHT,
self.output.setHalfbright)
underline = element(lambda code:code==cci.UNDERLINE,
self.output.setUnderline)
nounderline = element(lambda code:code==cci.NOUNDERLINE,
self.output.resetUnderline)
invert = element(lambda code:code==cci.INVERT,
self.output.setInvert)
noinvert = element(lambda code:code==cci.NOINVERT,
self.output.resetInvert)
normal = element(lambda code:code==cci.NORMAL,
resetBoldHalfbright)
reset_foreground = element(lambda code:code==cci.FOREGROUND_DEFAULT,
self.output.resetForeground)
reset_background = element(lambda code:code==cci.BACKGROUND_DEFAULT,
self.output.resetBackground)
foreground = self.ColorElement(begin=cci.FOREGROUND,
end=cci.FOREGROUND_END,action=self.output.setForeground)
background = self.ColorElement(begin=cci.BACKGROUND,
end=cci.BACKGROUND_END,action=self.output.setBackground)
self.grams = [reset,bold,halfbright,underline,nounderline,normal,
invert,noinvert,foreground,background]
def outputText(self,s):
return self.output.outputText(s)
def transform(self,s):
"""
Запустить преобразование текста
"""
def generator():
offset = len(self.escSymb)+1
for ctrl,txt in self.reParse.findall(s):
if ctrl:
codes = SavableIterator(ctrl[offset:-1].split(';'))
for code in codes:
code = int(code)
res = ""
for gram in ifilter(lambda x:x.tryParse(code),
self.grams):
res = gram.parse(code,codes)
break
if res:
yield res
if txt:
yield self.outputText(txt)
yield self.output.endText()
return "".join(list(filter(None,generator())))
class ConsoleCodes256Converter(ConsoleCodesConverter):
"""Расширяет возможность обработки 256 цветного терминала"""
class Color256Element(ConsoleCodesConverter.CodeElement):
def __init__(self,action=lambda x:None, begin=None):
self.action = action
self.begin = begin
def tryParse(self,code):
return code == self.begin
def parse(self,code,codes):
"""
Тон: 38;5;0-255
Фон: 48;5;0-255
"""
colorMap = LightColorMapping(BaseColorMapping).mapConsole_TS
codes.save()
if self._next_code(codes) == ConsoleCodesInfo.COLOR256:
code = self._next_code(codes)
if code is not None:
if code in colorMap:
self.action(colorMap[code])
else:
self.action(ConsoleColor256.consoleToRgb(code))
else:
# если после 38 не 5 - не обрабатываем этот код
codes.restore()
def __init__(self,*args,**kwargs):
ConsoleCodesConverter.__init__(self,*args,**kwargs)
cci = ConsoleCodesInfo
# обработчики кодов для вывода в 256
foreground256 = self.Color256Element(begin=cci.FOREGROUND256,
action=self.output.setForeground)
background256 = self.Color256Element(begin=cci.BACKGROUND256,
action=self.output.setBackground)
self.grams.insert(0,foreground256)
self.grams.insert(0,background256)

@ -0,0 +1,396 @@
#-*- coding: utf-8 -*-
# Copyright 2014 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from calculate.lib.utils.tools import SavableIterator
from palette import (TextState, BaseColorMapping,
ConsoleCodeMapping, LightColorMapping, ConsoleColor256,
ConsoleCodesInfo, SpanPalette)
class BaseOutput:
"""
Базовый вывод текста.
Вывод просто текста без изменения шрифта
"""
def __init__(self,state=None):
pass
def setBold(self):
"""
Выводимый текст будет жирным
"""
pass
def resetBold(self):
"""
Выводимый текст будет нежирным
"""
pass
def setUnderline(self):
"""
Выводимый текст будет подчеркнутым
"""
pass
def resetUnderline(self):
"""
Выводимый текст не будет подчеркнутым
"""
pass
def setHalfbright(self):
"""
Цвет выводимого текста использует полутона
"""
pass
def resetHalfbright(self):
"""
Цвет выводимого текста не использует полутона
"""
pass
def reset(self):
"""
Использовать шрифт по умолчанию
"""
pass
def endText(self):
"""
Обработка текста завершена
"""
return ""
def outputText(self,text):
"""
Вывести текст с установленными настройками
"""
return text
def setForeground(self,color):
"""
Установить цвет шрифта
"""
pass
def setBackground(self,color):
"""
Установить цвет фона
"""
pass
def resetForeground(self,color):
"""
Использовать цвет шрифта по умолчанию
"""
pass
def resetBackground(self,color):
"""
Использовать цвет фона по умолчанию
"""
pass
def setInvert(self):
"""
Включить инверсию
"""
def resetInvert(self):
"""
Выключить инверсию
"""
class SaveAttrOutput(BaseOutput):
"""
Базовый класс с сохранением атрибутов
"""
def __init__(self,state=None):
self.prev_state = state.clone() if state else TextState()
self.current_state = self.prev_state.clone()
def setBold(self):
self.current_state.bold = True
def resetBold(self):
self.current_state.bold = False
def setUnderline(self):
self.current_state.underline = True
def resetUnderline(self):
self.current_state.underline = False
def setHalfbright(self):
self.current_state.halfbright = True
def resetHalfbright(self):
self.current_state.halfbright = False
def reset(self):
self.resetBold()
self.resetHalfbright()
self.resetUnderline()
self.resetForeground()
self.resetBackground()
self.resetInvert()
def setForeground(self,color):
self.current_state.foreground = color
def resetForeground(self):
self.current_state.foreground = TextState.Colors.DEFAULT
def setBackground(self,color):
self.current_state.background = color
def resetBackground(self):
self.current_state.background = TextState.Colors.DEFAULT
def resetInvert(self):
self.current_state.invert = False
def setInvert(self):
self.current_state.invert = True
class ColorTerminalOutput(SaveAttrOutput):
"""
Форматирует текст для вывода в консоль
"""
mapColors = ConsoleCodeMapping(ConsoleCodesInfo.FOREGROUND,
BaseColorMapping).mapTS_Console
mapLightColors = ConsoleCodeMapping(ConsoleCodesInfo.FOREGROUND-
LightColorMapping.offset,
LightColorMapping).mapTS_Console
mapBackgroundColors = ConsoleCodeMapping(ConsoleCodesInfo.BACKGROUND,
BaseColorMapping).mapTS_Console
def setBold(self):
self.resetHalfbright()
SaveAttrOutput.setBold(self)
def setHalfbright(self):
self.resetBold()
SaveAttrOutput.setHalfbright(self)
def handleForeground(self,prevstate,curstate,attrs):
cci = ConsoleCodesInfo
color = curstate.foreground
if color in self.mapColors:
attrs.append(self.mapColors[color])
elif color in self.mapLightColors:
if prevstate.bold == curstate.bold and curstate.bold == False:
attrs.append(cci.BOLD)
attrs.append(self.mapLightColors[color])
else:
attrs.append(cci.FOREGROUND_DEFAULT)
self.resetForeground()
def handleBackground(self,prevstate,curstate,attrs):
color = curstate.background
if color in self.mapBackgroundColors:
attrs.append(self.mapBackgroundColors[color])
else:
attrs.append(ConsoleCodesInfo.BACKGROUND_DEFAULT)
def handleIntensity(self,prevstate,curstate,attrs):
if curstate.bold and curstate.bold != prevstate.bold:
attrs.append(ConsoleCodesInfo.BOLD)
elif (curstate.halfbright and
prevstate.halfbright != curstate.halfbright):
attrs.append(ConsoleCodesInfo.HALFBRIGHT)
else:
attrs.append(ConsoleCodesInfo.NORMAL)
def handleUnderline(self,prevstate,curstate,attrs):
if curstate.underline:
attrs.append(ConsoleCodesInfo.UNDERLINE)
else:
attrs.append(ConsoleCodesInfo.NOUNDERLINE)
def handleInvert(self,prevstate,curstate,attrs):
if curstate.invert:
attrs.append(ConsoleCodesInfo.INVERT)
else:
attrs.append(ConsoleCodesInfo.NOINVERT)
def _createAttrs(self,prevstate,curstate):
"""
Создать ESC последовательность для установки параметров текста
"""
attrs = []
# получить интенсивность (полутон и жирность относятся к интенсивности)
intensity = lambda x:x & (TextState.Attributes.HALFBRIGHT |
TextState.Attributes.BOLD)
if (prevstate.attr != curstate.attr and
curstate.attr == TextState.Attributes.NONE and
curstate.foreground is TextState.Colors.DEFAULT and
curstate.background is TextState.Colors.DEFAULT):
attrs.append(ConsoleCodesInfo.RESET)
else:
if intensity(prevstate.attr) != intensity(curstate.attr):
self.handleIntensity(prevstate,curstate,attrs)
if prevstate.underline != curstate.underline:
self.handleUnderline(prevstate,curstate,attrs)
if prevstate.invert != curstate.invert:
self.handleInvert(prevstate,curstate,attrs)
if prevstate.foreground != curstate.foreground:
self.handleForeground(prevstate,curstate,attrs)
if prevstate.background != curstate.background:
self.handleBackground(prevstate,curstate,attrs)
return attrs
def handlePostAttr(self,prevstate,curstate):
"""
Добавление аттрибутов после выведенного текста
"""
if prevstate.foreground != curstate.foreground:
color = curstate.foreground
if (color in self.mapLightColors and
prevstate.bold == curstate.bold and curstate.bold == False):
return [ConsoleCodesInfo.NORMAL]
def _createEscCode(self,attrs):
"""
Создать ESC строку
"""
attrs = map(str,['\033['] + attrs + ['m'])
return "%s%s%s"%(attrs[0],";".join(attrs[1:-1]),attrs[-1])
def outputText(self,s):
"""
Задание параметров текста и вывод его
"""
if self.prev_state != self.current_state:
attr = self._createAttrs(self.prev_state,self.current_state)
attr = self._createEscCode(attr)
postattr = self.handlePostAttr(self.prev_state,self.current_state)
if postattr:
postattr = self._createEscCode(postattr)
else:
postattr = ""
self.prev_state = self.current_state.clone()
else:
attr = ""
postattr = ""
return attr + s + postattr
def endText(self):
self.reset()
return self.outputText("")
class ColorTerminal256Output(ColorTerminalOutput):
"""
Вывод на 256 цветный терминал
"""
mapLightColors = LightColorMapping.mapTS_Console
def handleForeground(self,prevstate,curstate,attrs):
color = curstate.foreground
color256 = ConsoleColor256.rgbToConsole(color)
if not color256 and color in self.mapLightColors:
color256 = self.mapLightColors[color]
if color256:
attrs.extend([ConsoleCodesInfo.FOREGROUND256,
ConsoleCodesInfo.COLOR256,
color256])
else:
ColorTerminalOutput.handleForeground(self,prevstate,curstate,attrs)
def handleBackground(self,prevstate,curstate,attrs):
color = curstate.background
color256 = ConsoleColor256.rgbToConsole(color)
if not color256 and color in self.mapLightColors:
color256 = self.mapLightColors[color]
if color256:
attrs.extend([ConsoleCodesInfo.BACKGROUND256,
ConsoleCodesInfo.COLOR256,
color256])
else:
ColorTerminalOutput.handleBackground(self,prevstate,curstate,attrs)
def handlePostAttr(self,prevstate,curstate):
pass
class SpanCssOutput(SaveAttrOutput):
"""
Форматирует текст для вывода в консоль
"""
def __init__(self,state=None,palette=SpanPalette()):
SaveAttrOutput.__init__(self,state=state)
self.palette = palette
def getStringColor(self,color,bold=False,halfbright=False,background=False):
"""
Получить название цвета по номеру и состоянию текста
"""
if halfbright:
bright = SpanPalette.LOW_BRIGHT
elif bold:
bright = SpanPalette.HIGH_BRIGHT
else:
bright = SpanPalette.NORMAL_BRIGHT
if background:
return self.palette.getBackgroundColor(color)
else:
return self.palette.getTextColor(color,bright)
def getTags(self,prevstate,curstate):
"""
Создать ESC последовательность для установки параметров текста
"""
style = []
colorAttr = ["color","background"]
if curstate.invert:
colorAttr = colorAttr[1],colorAttr[0]
if (prevstate.foreground != curstate.foreground or
prevstate.bold != curstate.bold or
curstate.invert or
prevstate.halfbright != curstate.halfbright):
sColor = self.getStringColor(curstate.foreground,
curstate.bold,
curstate.halfbright,
background=False)
style.append("%s:%s;"%(colorAttr[0],sColor))
if prevstate.background != curstate.background or curstate.invert:
sColor = self.getStringColor(curstate.background,background=True)
style.append("%s:%s;"%(colorAttr[1],sColor))
if prevstate.underline != curstate.underline:
if curstate.underline:
style.append("text-decoration:underline;")
else:
style.append("text-decoration:none;")
if prevstate.bold != curstate.bold:
if curstate.bold:
style.append("font-weight:bold;")
else:
style.append("font-weight:normal;")
return '<span style="%s">'%"".join(style),'</span>'
def outputText(self,s):
if self.prev_state != self.current_state:
lattr, rattr = self.getTags(self.prev_state,self.current_state)
else:
lattr = rattr = ""
return lattr + s + rattr
def endText(self):
self.reset()
return ""

@ -0,0 +1,318 @@
#-*- coding: utf-8 -*-
# Copyright 2014 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
import re
from itertools import chain,ifilter,tee
from os import path
class ConsoleCodesInfo:
"""
Коды цветов
"""
COLORCOUNT = 8
BLACK, RED, GREEN, BROWN, BLUE, PURPLE, CYAN, WHITE = range(0,COLORCOUNT)
DEFAULT = 9
FOREGROUND = 30
FOREGROUND_DEFAULT = 39
FOREGROUND_END = 37
BACKGROUND = 40
BACKGROUND_DEFAULT = 49
BACKGROUND_END = 47
BOLD = 1
HALFBRIGHT = 2
UNDERLINE = 4
NOUNDERLINE = 24
NORMAL = 22
RESET = 0
FOREGROUND256 = 38
COLOR256 = 5
BACKGROUND256 = 48
INVERT = 7
NOINVERT = 27
class ConsoleColor256:
"""Объект перевода RGB цветов в консоль 256color"""
colorList = (0,95,135,175,215,255)
colorMatch = [colorList[x]+(colorList[x+1]-colorList[x])/2
for x in range(0,5)] + [255]
colorHex = ["%02x"%val for val in colorList]
webMatch = re.compile("^#[0-9A-Fa-f]{6}$")
grayMatch = [6 + x * 11 for x in xrange(0,23)] + [255]
@staticmethod
def rgbToConsole(color):
"""Перевести RGB в 256 консоль
>>> ConsoleColor256.rgbToConsole("#5f00ff")
57
>>> ConsoleColor256.rgbToConsole("not #rrggbb") is None
True
"""
if color and ConsoleColor256.webMatch.match(color):
color = [int(x,base=16) for x in (color[5:7],color[3:5],color[1:3])]
# grayscale match
if abs(color[0]-color[1]) + abs(color[0]-color[2]) < 5:
for j,matchGray in enumerate(ConsoleColor256.grayMatch):
if color[0] <= matchGray:
return 232+j
# color match
colorNumber = 16
for i,_color in enumerate(color):
for j,halfColor in enumerate(ConsoleColor256.colorMatch):
if _color <= halfColor:
colorNumber += j * 6 ** i
break
return colorNumber
return None
@staticmethod
def consoleToRgb(color):
"""
Перевести 256 консоль в #RGB
>>> ConsoleColor256.consoleToRgb(216)
'#ffaf87'
>>> ConsoleColor256.consoleToRgb(15) is None
True
"""
if color >= 255:
return "#ffffff"
if color >= 232:
return "#{0:02x}{0:02x}{0:02x}".format((color-232)*11)
elif color >=16:
color-= 16
return "#%s"%"".join(ConsoleColor256.colorHex[color/x%6]
for x in (36,6,1))
else:
return None
class TextState(object):
"""
Параметры текста
>>> ts = TextState()
>>> ts.attr = TextState.Attributes.BOLD | TextState.Attributes.UNDERLINE
>>> ts.bold
True
>>> ts.underline
True
>>> ts.halfbright
False
"""
class Attributes:
NONE = 0
BOLD = 1
HALFBRIGHT = 2
UNDERLINE = 4
INVERT = 8
class Colors:
# обычные цвета
BLACK = "black"
RED = "red"
GREEN = "green"
BROWN = "brown"
BLUE = "blue"
PURPLE = "purple"
CYAN = "cyan"
GRAY = "gray"
# яркие цвета
DARK = "dark"
LIGHT_RED = "lightred"
LIGHT_GREEN = "lightgreen"
YELLOW = "yellow"
LIGHT_BLUE = "lightblue"
LIGHT_PURPLE = "lightpurple"
LIGHT_CYAN = "lightcyan"
WHITE = "white"
# темные цвета (консоль пониженной яркости)
DARK_BLACK = "darkblack"
DARK_RED = "darkred"
DARK_GREEN = "darkgreen"
DARK_BROWN = "darkbrown"
DARK_BLUE = "darkblue"
DARK_PURPLE = "darkpurple"
DARK_CYAN = "darkcyan"
DARK_GRAY = "darkgray"
DEFAULT = None
normalColors = [Colors.BLACK,Colors.RED,Colors.GREEN,Colors.BROWN,
Colors.BLUE,Colors.PURPLE,Colors.CYAN,Colors.GRAY]
lightColors = [Colors.DARK,Colors.LIGHT_RED,Colors.LIGHT_GREEN,
Colors.YELLOW,Colors.LIGHT_BLUE,Colors.LIGHT_PURPLE,
Colors.LIGHT_CYAN,Colors.WHITE]
darkColors = [Colors.DARK_BLACK,Colors.DARK_RED,Colors.DARK_GREEN,
Colors.DARK_BROWN,Colors.DARK_BLUE,Colors.DARK_PURPLE,
Colors.DARK_CYAN,Colors.DARK_GRAY]
def bitProperty(bit):
def set(self,value):
self.attr&=~bit
self.attr|=bit if value else 0
def get(self):
return bool(self.attr & bit)
return property(get,set)
# текст с подчеркиванием
underline = bitProperty(Attributes.UNDERLINE)
# текст жирный
bold = bitProperty(Attributes.BOLD)
# пониженная яркость
halfbright = bitProperty(Attributes.HALFBRIGHT)
# инверсия
invert = bitProperty(Attributes.INVERT)
def __init__(self,foreground=Colors.DEFAULT,
background=Colors.DEFAULT,
attr=Attributes.NONE):
self.foreground = foreground
self.background = background
self.attr = attr
def clone(self):
return self.__class__(self.foreground,self.background,
self.attr)
def __cmp__(self,other):
for i in ["foreground","background","attr"]:
cmp_res = cmp(getattr(self,i),getattr(other,i))
if cmp_res:
return cmp_res
return 0
@classmethod
def colors(cls):
return chain(xrange(0,8),[None])
class BaseColorMapping:
# соответствие внутренних цветов консольным
mapConsole_TS = {ConsoleCodesInfo.BLACK: TextState.Colors.BLACK,
ConsoleCodesInfo.RED: TextState.Colors.RED,
ConsoleCodesInfo.GREEN: TextState.Colors.GREEN,
ConsoleCodesInfo.BROWN: TextState.Colors.BROWN,
ConsoleCodesInfo.BLUE: TextState.Colors.BLUE,
ConsoleCodesInfo.PURPLE:TextState.Colors.PURPLE,
ConsoleCodesInfo.CYAN: TextState.Colors.CYAN,
ConsoleCodesInfo.WHITE: TextState.Colors.GRAY}
mapTS_Console = {v:k for k,v in mapConsole_TS.items()}
def __init__(self,base):
self.mapConsole_TS = self.mapConsole_TS.copy()
self.mapConsole_TS.update(base.mapConsole_TS)
self.mapTS_Console = {v:k for k,v in self.mapConsole_TS.items()}
class LightColorMapping(BaseColorMapping):
# соответствие внутренних цветов консольным
offset = ConsoleCodesInfo.COLORCOUNT
mapConsole_TS = {ConsoleCodesInfo.BLACK+offset: TextState.Colors.DARK,
ConsoleCodesInfo.RED+offset: TextState.Colors.LIGHT_RED,
ConsoleCodesInfo.GREEN+offset: TextState.Colors.LIGHT_GREEN,
ConsoleCodesInfo.BROWN+offset: TextState.Colors.YELLOW,
ConsoleCodesInfo.BLUE+offset: TextState.Colors.LIGHT_BLUE,
ConsoleCodesInfo.PURPLE+offset:TextState.Colors.LIGHT_PURPLE,
ConsoleCodesInfo.CYAN+offset: TextState.Colors.LIGHT_CYAN,
ConsoleCodesInfo.WHITE+offset: TextState.Colors.WHITE}
mapTS_Console = {v:k for k,v in mapConsole_TS.items()}
class ConsoleCodeMapping(BaseColorMapping):
"""
Декоратор для преобразования кодов цвета в код цвета тона или фона
Добавляет смещение к коду (3 -> 3 + codeoffset)
"""
def __init__(self,codeoffset,base):
self.mapConsole_TS = {codeoffset+k:v for k,v in base.mapConsole_TS.items()}
self.mapTS_Console = {v:k for k,v in self.mapConsole_TS.items()}
class SpanPalette:
"""
Палитра для SpanCssOutput (черное на белом)
"""
LOW_BRIGHT, NORMAL_BRIGHT, HIGH_BRIGHT = 0, 1, 2
defaultColor = ["Black","Black","DarkGrey"]
defaultBackground = "White"
normalBright = dict(zip(TextState.normalColors,
["Black","DarkRed","DarkGreen",
"Sienna","DarkBlue","DarkViolet",
"LightSeaGreen","Grey"]))
highBright = dict(zip(TextState.lightColors,
["DarkGrey","Red","Green",
"Yellow","RoyalBlue","Magenta",
"Cyan","White"]))
lowBright = dict(zip(TextState.darkColors,
["Black","Maroon","DarkGreen",
"SaddleBrown","DarkBlue","DarkViolet",
"LightSeaGreen","Grey"]))
mapHighNormal = dict(zip(TextState.normalColors,
TextState.lightColors))
mapLowNormal = dict(zip(TextState.normalColors,
TextState.darkColors))
def __init__(self):
self.colorMap = dict(self.normalBright.items()+
self.highBright.items()+
self.lowBright.items())
self.brightMap = {self.NORMAL_BRIGHT:{},
self.HIGH_BRIGHT:self.mapHighNormal,
self.LOW_BRIGHT:self.mapLowNormal}
def brightTransform(self,color,bright):
"""
Преобразовать основной цвет в зависимости от установленной яркости
"""
mapper = self.brightMap.get(bright,{})
return mapper.get(color,color)
def getBackgroundColor(self,color):
if not color:
return self.defaultBackground
return self.colorMap.get(color,color)
def getTextColor(self,color,bright):
"""
Получить соответствие цвета строкой
"""
if not color:
return self.defaultColor[bright]
color = self.brightTransform(color,bright)
return self.colorMap.get(color,color)
class DarkPastelsPalette(SpanPalette):
"""
Палитра идентичная Calculate в консоли (Dark Pastels)
"""
defaultColor = ["#DCDCDC","#DCDCDC","#709080"]
defaultBackground = "#2C2C2C"
normalBright = dict(zip(TextState.normalColors,
["#2C2C2C","#705050","#60B48A", "#DFAF8F",
"#9AB8D7","#DC8CC3","#8CD0D3","#DCDCDC"]))
highBright = dict(zip(TextState.lightColors,
["#709080","#DCA3A3","#72D5A3", "#F0DFAF",
"#94BFF3","#EC93D3","#93E0E3","#FFFFFF"]))

@ -27,116 +27,6 @@ from re import search, compile, S
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_lib3',sys.modules[__name__])
def prettyColumnStr(*cols):
'''Функция преобразования строк в текстовые колонки. Если указанный текст
не помещается в колонку, то строка переносится на следующую этой же колонки
перенос текста идет по словам, и текст выравнивается по ширине колонки за
счет дополнительных пробелов между словами. Если в строке используется
перенос строки, то текст переносится не просто на следующую строку, а также
на следующую строку колонки, причем если используется \r текст выравнива-
ется по ширине, а если \n, то просто перевод строки.
Параметры:
cols множестово пар: текст, ширина колонки, причем, если у последней
колонки не указывать ширину, то она будет выведена вся.
Возвращаемые параметры:
строка, которую можно использовать для вывода на экран
Пример: columnWrite( "Some text", 10, "Next column", 20 )
'''
# шаблон поиска переводов строк
wherenr = compile( '[\n\r]', S )
retstr = ""
# перевести кортеж в список, т.к. изменяется
cols = list(cols)
# перевести текст в юникод, заодно перевести числа в строку
noconvert = False
space = u' '
nospace = u''
for i in xrange(0,len(cols),2):
cols[i] = _toUNICODE(cols[i])
# флаг "есть еще текст для вывода"
repeat = True
while repeat:
# сбросить итератор на первый элемент
q = 0
repeat = False
# пока не закончили перебирать параметры (перебираем по парам)
while q < len(cols):
# если это последний параметр, и для него не указана ширина
if q == len(cols)-1:
# выводим его полностью не смотря на ширину окна
retstr += cols[q] + " "
cols[q] = ''
else:
# вывести часть строки не больше указанной ширины колонки
partstr = cols[q][:cols[q+1]]
# искать перевод строки с полученной части
brfind = wherenr.search(partstr)
# если это не последняя колонка
if q + 2 < len(cols):
# добавить разделитель между колонками
cellspacing = space
else:
# разделитель не нужен
cellspacing = nospace
# если перевод строки найден, то
if brfind != None:
# для текущего вывода в колонку
# берем часть строки до перевода
partstr = partstr[:brfind.start()]
# остальная часть идет в остаток (без перевода)
cols[q] = cols[q][brfind.start()+1:]
# # если используется перевод каретки
# if brfind.group() == '\r':
# # то выравниваем по ширине колонки
# partstr = partstr.ljust(cols[q+1], ' ')
# else:
# # добавить отступы чтобы закончить колонку
partstr = partstr.ljust(cols[q+1], ' ')
# если взята часть строки
elif len(partstr) == cols[q+1] and partstr != cols[q]:
# если взята часть строки (разрыв в слове)
if cols[q][cols[q+1]] != ' ':
# ищем ближайший пробел справа
spacepos = partstr.rfind(' ')
# если пробел найти не удалось
if spacepos == -1:
# то на вывод идет часть строки равной ширине
cols[q] = cols[q][cols[q+1]:]
# если пробел найден
else:
# обрезаем строку до найденного пробела
partstr = partstr[:spacepos]
cols[q] = cols[q][spacepos+1:]
# если взята часть строки (разрыв на пробеле)
else:
# ислючить переносной пробел
cols[q] = cols[q][cols[q+1]+1:]
# выровнить текст по ширине колонки
partstr = partstr.ljust(cols[q+1], ' ')
#partstr = justify(partstr, cols[q+1])
# остатки строки
else:
# добавить отступы чтобы закончить колонку
partstr = partstr.ljust(cols[q+1], ' ')
cols[q] = ''
retstr+= partstr + cellspacing
# остальную часть строки оставить на следующую итерацию
# если от строки что то осаталось
if len(cols[q]) > 0:
# отметить запуск еще одной итерации по параметрам
repeat = True
# следующая пара
q += 2
# колонки отображены
retstr += "\n"
return retstr.encode('utf8')
def columnMatrix(*cols):
"""
Split columns text to matrix

@ -0,0 +1,36 @@
#-*- coding: utf-8 -*-
# Copyright 2014 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from itertools import tee
class SavableIterator:
def __init__(self,seq):
self.seq = iter(seq)
self.back = None
def __iter__(self):
return self
def save(self):
self.seq, self.back = tee(self.seq)
def restore(self):
if self.back:
self.seq, self.back = tee(self.back)
def next(self):
return self.seq.next()

@ -43,7 +43,8 @@ setup(
module_name + '.server',
module_name + '.variables',
module_name + '.mod',
module_name + '.utils'],
module_name + '.utils',
module_name + '.utils.color'],
data_files = [("/etc/calculate", []),
("/var/calculate/remote", []),
("/var/log/calculate", [])]

Loading…
Cancel
Save