about summary refs log tree commit diff stats
path: root/html/factorial.mu.html
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2019-04-03 23:09:31 -0700
committerKartik Agaram <vc@akkartik.com>2019-04-03 23:09:31 -0700
commite174caf4d48d9f858735696d1043d188cecd5cb4 (patch)
treef3296f399ef96779b4ae3505ea1a6368a65f00e7 /html/factorial.mu.html
parent1c1889172ef8f7f14fe0c28daaddf4117cafd567 (diff)
downloadmu-e174caf4d48d9f858735696d1043d188cecd5cb4.tar.gz
5054
Diffstat (limited to 'html/factorial.mu.html')
0 files changed, 0 insertions, 0 deletions
'>106 107 108
' href='#n109'>109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# Copyright (C) 2010 David Barnett <davidbarnett2@gmail.com>
# Copyright (C) 2010, 2011  Roman Zimbelmann <romanz@lavabit.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""
A library to help to convert ANSI codes to curses instructions.
"""

from ranger.gui import color
import re

ansi_re = re.compile('(\x1b' + r'\[\d*(?:;\d+)*?[a-zA-Z])')
reset = '\x1b[0m'

def split_ansi_from_text(ansi_text):
	return ansi_re.split(ansi_text)

def text_with_fg_bg_attr(ansi_text):
	for chunk in split_ansi_from_text(ansi_text):
		if chunk and chunk[0] == '\x1b':
			if chunk[-1] != 'm':
				continue
			match = re.match(r'^.\[(.*).$', chunk)
			attr_args = match.group(1)
			fg, bg, attr = -1, -1, 0

			# Convert arguments to attributes/colors
			for arg in attr_args.split(';'):
				try:
					n = int(arg)
				except:
					if arg == '':
						n = 0
					else:
						continue
				if n == 0:
					fg, bg, attr = -1, -1, 0
				elif n == 1:
					attr |= color.bold
				elif n == 4:
					attr |= color.underline
				elif n == 5:
					attr |= color.blink
				elif n == 7:
					attr |= color.reverse
				elif n == 8:
					attr |= color.invisible
				elif n >= 30 and n <= 37:
					fg = n - 30
				elif n == 39:
					fg = -1
				elif n >= 40 and n <= 47:
					bg = n - 40
				elif n == 49:
					bg = -1
			yield (fg, bg, attr)
		else:
			yield chunk

def char_len(ansi_text):
	"""
	Count the number of visible characters.

	>>> char_len("\x1b[0;30;40mX\x1b[0m")
	1
	>>> char_len("\x1b[0;30;40mXY\x1b[0m")
	2
	>>> char_len("\x1b[0;30;40mX\x1b[0mY")
	2
	>>> char_len("hello")
	5
	>>> char_len("")
	0
	"""
	return len(ansi_re.sub('', ansi_text))

def char_slice(ansi_text, start, end):
	"""
	>>> ansi_string = "\x1b[0;30;40mX\x1b[0;31;41mY\x1b[0m"
	>>> char_slice(ansi_string, 0, 1)
	'\\x1b[0;30;40mX'

	# XXX: Does not work as expected:
	# >>> char_slice(ansi_string, 1, 2)
	# '\\x1b[0;31;41mY'
	"""
	slice_chunks = []
	# skip to start
	last_color = None
	skip_len_left = start
	len_left = end - start
	for chunk in split_ansi_from_text(ansi_text):
		m = ansi_re.match(chunk)
		if m:
			if chunk[-1] == 'm':
				last_color = chunk
		else:
			if skip_len_left > len(chunk):
				skip_len_left -= len(chunk)
			else:		# finished skipping to start
				if skip_len_left > 0:
					chunk = chunk[skip_len_left:]
				chunk_left = chunk[:len_left]
				if len(chunk_left):
					if last_color is not None:
						slice_chunks.append(last_color)
					slice_chunks.append(chunk_left)
					len_left -= len(chunk_left)
				if len_left == 0:
					break
	return ''.join(slice_chunks)

if __name__ == '__main__':
	import doctest
	doctest.testmod()