1# -*- coding: utf-8 -*- 2 3# Copyright (C) 2005 Osmo Salomaa 4# 5# This program is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18"""Text markup for the MPL2 format.""" 19 20import aeidon 21 22from collections import OrderedDict 23 24__all__ = ("MPL2",) 25 26 27class MPL2(aeidon.markups.MicroDVD): 28 29 """ 30 Text markup for the MPL2 format. 31 32 MPL2 contains the following markup tags, all of which appear at the 33 beginning of the line and affect up to the end of the line. In addition, 34 any MicroDVD markup can be used. 35 36 * ``\\...`` (bold) 37 * ``/....`` (italic) 38 * ``_....`` (underline) 39 """ 40 41 format = aeidon.formats.MPL2 42 43 def bolden(self, text, bounds=None): 44 """Return bolded `text`.""" 45 return self._style_mpl2(text, "\\", bounds) 46 47 @property 48 def italic_tag(self): 49 """Regular expression for an italic markup tag.""" 50 return self._get_regex(r"(^/)|(\{[Yy]:i\})") 51 52 def italicize(self, text, bounds=None): 53 """Return italicized `text`.""" 54 return self._style_mpl2(text, "/", bounds) 55 56 def _main_decode(self, text): 57 """Return `text` with decodable markup decoded.""" 58 text = self._decode_b(text, r"<\\>(.*?)</\\>", 1) 59 text = self._decode_i(text, r"</>(.*?)<//>", 1) 60 text = self._decode_u(text, r"<_>(.*?)</_>", 1) 61 return aeidon.markups.MicroDVD._main_decode(self, text) 62 63 def _pre_decode(self, text): 64 """Return `text` with markup prepared for decoding.""" 65 text = self._pre_decode_identify(text) 66 return aeidon.markups.MicroDVD._pre_decode(self, text) 67 68 def _pre_decode_identify(self, text): 69 """ 70 Return `text` with all tags identified and closed. 71 72 ``\\``, ``/`` and ``_`` characters at the beginnings of lines are 73 identified as tags and replaced with artificial tags ``<\\>``, ``</>`` 74 and ``<_>``. Closing tags are added to the ends of lines as artificial 75 tags ``</\\>``, ``<//>`` and ``</_>``. 76 """ 77 lines = text.split("\n") 78 re_tag = self._get_regex(r"^([\\/_]+)(.*)$") 79 for i, line in enumerate(lines): 80 match = re_tag.search(line) 81 if match is None: continue 82 lines[i] = match.group(2) 83 for tag in reversed(OrderedDict.fromkeys(match.group(1))): 84 lines[i] = "<{}>{}</{}>".format(tag, lines[i], tag) 85 return "\n".join(lines) 86 87 def _style_mpl2(self, text, tag, bounds=None): 88 """Return `text` wrapped in markup `tag`.""" 89 a, z = bounds or (0, len(text)) 90 prefix = text[:a].split("\n")[-1] 91 suffix = text[z:].split("\n")[0] 92 re_alpha = self._get_regex(r"\w") 93 # Return plain text if bounds does not define an entire line or 94 # subtitle and thus cannot be marked without side-effects. 95 if re_alpha.search(prefix): return text 96 if re_alpha.search(suffix): return text 97 styled_text = text[a:z].replace("\n", "\n{}".format(tag)) 98 return "".join((text[:a], tag, styled_text, text[z:])) 99 100 @property 101 def tag(self): 102 """Regular expression for any markup tag.""" 103 return self._get_regex(r"(^[\\/_]+)|(\{[CFSYcfsy]:.*?\})") 104 105 def underline(self, text, bounds=None): 106 """Return underlined `text`.""" 107 return self._style_mpl2(text, "_", bounds) 108