| @@ -32,6 +32,6 @@ __license__ = "MIT License" | |||||
| __version__ = "0.1.dev" | __version__ = "0.1.dev" | ||||
| __email__ = "ben.kurtovic@verizon.net" | __email__ = "ben.kurtovic@verizon.net" | ||||
| from mwparserfromhell import nodes, parser, string_mixin, wikicode | |||||
| from mwparserfromhell import nodes, parser, smart_list, string_mixin, wikicode | |||||
| parse = lambda text: parser.Parser(text).parse() | parse = lambda text: parser.Parser(text).parse() | ||||
| @@ -22,6 +22,7 @@ | |||||
| from mwparserfromhell.nodes import Template, Text | from mwparserfromhell.nodes import Template, Text | ||||
| from mwparserfromhell.nodes.extras import Parameter | from mwparserfromhell.nodes.extras import Parameter | ||||
| from mwparserfromhell.smart_list import SmartList | |||||
| from mwparserfromhell.wikicode import Wikicode | from mwparserfromhell.wikicode import Wikicode | ||||
| __all__ = ["DemoParser"] | __all__ = ["DemoParser"] | ||||
| @@ -48,5 +49,5 @@ class DemoParser(object): | |||||
| node4_param2 = Parameter(node4_param2_name, node4_param2_value, showkey=True) | node4_param2 = Parameter(node4_param2_name, node4_param2_value, showkey=True) | ||||
| node4 = Template(Wikicode([Text(u"template")]), [node4_param1, node4_param2]) | node4 = Template(Wikicode([Text(u"template")]), [node4_param1, node4_param2]) | ||||
| node5 = Text(u".") | node5 = Text(u".") | ||||
| parsed = Wikicode([node1, node2, node3, node4, node5]) | |||||
| parsed = Wikicode(SmartList([node1, node2, node3, node4, node5])) | |||||
| return parsed | return parsed | ||||
| @@ -0,0 +1,91 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| # | |||||
| # Copyright (C) 2012 Ben Kurtovic <ben.kurtovic@verizon.net> | |||||
| # | |||||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
| # of this software and associated documentation files (the "Software"), to deal | |||||
| # in the Software without restriction, including without limitation the rights | |||||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
| # copies of the Software, and to permit persons to whom the Software is | |||||
| # furnished to do so, subject to the following conditions: | |||||
| # | |||||
| # The above copyright notice and this permission notice shall be included in | |||||
| # all copies or substantial portions of the Software. | |||||
| # | |||||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
| # SOFTWARE. | |||||
| import sys | |||||
| __all__ = ["SmartList"] | |||||
| class SmartList(list): | |||||
| def __init__(self, iterable=None): | |||||
| if iterable: | |||||
| super(SmartList, self).__init__(iterable) | |||||
| else: | |||||
| super(SmartList, self).__init__() | |||||
| self._children = {} | |||||
| def __getslice__(self, start, stop): | |||||
| sublist = super(SmartList, self).__getslice__(start, stop) | |||||
| sliceinfo = [start, stop, 1] | |||||
| child = _ListProxy(self, sliceinfo) | |||||
| self._children[id(child)] = (child, sliceinfo) | |||||
| return child | |||||
| # def __setslice__(self, start, stop): | |||||
| def append(self, obj): | |||||
| super(SmartList, self).append(obj) | |||||
| for child, (start, stop, step) in self._children.itervalues(): | |||||
| if stop >= len(self) - 1 and stop != sys.maxint: | |||||
| self._children[id(child)][1][1] += 1 | |||||
| class _ListProxy(list): | |||||
| def __init__(self, parent, sliceinfo): | |||||
| super(_ListProxy, self).__init__() | |||||
| self._parent = parent | |||||
| self._sliceinfo = sliceinfo | |||||
| def __len__(self): | |||||
| return (self._stop - self._start) / self._step | |||||
| def __iter__(self): | |||||
| i = self._start | |||||
| while i < self._stop: | |||||
| yield self._parent[i] | |||||
| i += self._step | |||||
| def __getitem__(self, index): | |||||
| return self._render()[index] | |||||
| def __getslice__(self, start, stop): | |||||
| return self._render()[start:stop] | |||||
| @property | |||||
| def _start(self): | |||||
| return self._sliceinfo[0] | |||||
| @property | |||||
| def _stop(self): | |||||
| return self._sliceinfo[1] | |||||
| @property | |||||
| def _step(self): | |||||
| return self._sliceinfo[2] | |||||
| def _render(self): | |||||
| return self._parent[self._start:self._stop:self._step] | |||||
| def append(self, obj): | |||||
| self._parent.insert(self._stop, obj) | |||||
| def insert(self, index, obj): | |||||
| self._parent.insert(self._start + index, obj) | |||||
| @@ -21,8 +21,9 @@ | |||||
| # SOFTWARE. | # SOFTWARE. | ||||
| import re | import re | ||||
| import sys | |||||
| from mwparserfromhell.nodes import Node, Tag, Template, Text | |||||
| from mwparserfromhell.nodes import Heading, Node, Tag, Template, Text | |||||
| from mwparserfromhell.string_mixin import StringMixIn | from mwparserfromhell.string_mixin import StringMixIn | ||||
| from mwparserfromhell.utils import parse_anything | from mwparserfromhell.utils import parse_anything | ||||
| @@ -190,6 +191,34 @@ class Wikicode(StringMixIn): | |||||
| def filter_tags(self, recursive=False, matches=None, flags=FLAGS): | def filter_tags(self, recursive=False, matches=None, flags=FLAGS): | ||||
| return list(self.ifilter_tags(recursive, matches, flags)) | return list(self.ifilter_tags(recursive, matches, flags)) | ||||
| def get_sections(self, flat=True, matches=None, levels=None, flags=FLAGS, | |||||
| include_headings=True): | |||||
| if matches: | |||||
| matches = r"^(=+?)\s*" + matches + r"\s*\1$" | |||||
| headings = self.filter(recursive=True, matches=matches, flags=flags, | |||||
| forcetype=Heading) | |||||
| if levels: | |||||
| headings = [head for head in headings if head.level in levels] | |||||
| sections = [] | |||||
| buffers = [[sys.maxint, 0]] | |||||
| i = 0 | |||||
| while i < len(self.nodes): | |||||
| if self.nodes[i] in headings: | |||||
| this = self.nodes[i].level | |||||
| for (level, start) in buffers: | |||||
| if not flat or this <= level: | |||||
| buffers.remove([level, start]) | |||||
| sections.append(self.nodes[start:i]) | |||||
| buffers.append([this, i]) | |||||
| if not include_headings: | |||||
| i += 1 | |||||
| i += 1 | |||||
| for (level, start) in buffers: | |||||
| if start != i: | |||||
| sections.append(self.nodes[start:i]) | |||||
| return sections | |||||
| def strip_code(self, normalize=True, collapse=True): | def strip_code(self, normalize=True, collapse=True): | ||||
| nodes = [] | nodes = [] | ||||
| for node in self.nodes: | for node in self.nodes: | ||||