コード例 #1
0
ファイル: prettymd.py プロジェクト: akashb95/prettymd-py
    def construct_contents_tree(headings_list: List[Heading]) -> List[Heading]:
        """
        Constructs a Tree that represents the Contents from a flat List of :class:`Heading`.

        :param headings_list:
        :return:
        """

        if len(headings_list) == 0:
            return []

        # list of root Headings
        graph = []
        lowest_level = headings_list[0].level

        for i, heading in enumerate(headings_list):
            if heading.level <= lowest_level:

                if heading.level < lowest_level:
                    lowest_level = heading.level

                graph.append(heading)

            else:
                subheading = Heading(heading.val, heading.level, heading.start, heading.end)
                graph[-1].add_subheading(subheading)

        for heading in graph:
            subheadings = PrettyMD.construct_contents_tree(heading.subheadings)
            heading.set_subheadings(subheadings)

        return graph
コード例 #2
0
ファイル: prettymd.py プロジェクト: akashb95/prettymd-py
    def __init__(self, original: str, includes_title: bool = False, link: bool = True, back_to_toc_link: bool = True):
        """

        :param original: Input Markdown text.
        :param includes_title: Whether a Title is included in the input text. If so, it'll be excluded from the ToC.
        :param link: Whether to include hyperlinks from the ToC to the relevant headings.
        :param back_to_toc_link: Whether to include hyperlinks at end of each section that navigates to the ToC.
        """

        self._input = original
        self._output = ""
        self._includes_title = includes_title
        self._link = link
        self._navlink = back_to_toc_link

        self.title = None

        # Root node of Contents
        self._contents_tree = Heading(val=None, level=-1, start=0, end=0, subheadings=None, height=-1)

        # table of contents - need to join with \n
        self._toc_items = ["<a name='nav'></a>\n## Contents 🗺"]

        # Updates self._contents_tree - adds all Headings as subheadings. Still a mostly-flat structure.
        self.parse_headings()

        # if MD includes title, then don't put title in ToC, and put ToC's location to begin after the title.
        if self._includes_title:
            all_headings = self._contents_tree.subheadings[1:]
            self._toc_location = self._contents_tree.subheadings[0].end
        else:
            all_headings = self._contents_tree
            self._toc_location = 0

        # Make Contents Tree from list of Headings. Unflattened structure.
        self._contents_tree.set_subheadings(self.construct_contents_tree(all_headings))

        # update self._toc_items
        self.make_toc()
        return
コード例 #3
0
ファイル: prettymd.py プロジェクト: akashb95/prettymd-py
    def flatten_contents_tree(self, heading: Heading) -> List[Heading]:
        """
        In-order traversal of :instance_attribute:`self._contents_tree`

        :return:
        """

        flat_contents_tree = [
            Heading(val=heading.val, level=heading.level, height=heading.height, start=heading.start, end=heading.end)]

        if len(heading) == 0:
            return flat_contents_tree

        for subheading in heading.subheadings:
            flat_contents_tree.extend(self.flatten_contents_tree(subheading))

        return flat_contents_tree
コード例 #4
0
ファイル: prettymd.py プロジェクト: akashb95/prettymd-py
    def parse_headings(self) -> None:
        """
        Finds using RegEx the headings in :instance_attribute:`self._input`. Add all these headings to the root of the
        contents tree, that is the :instance_attribute:`self._contents_tree`.

        :return:
        """

        # find all headings by matching regex
        headings_iterator = re.finditer(self.HEADING_REGEX, self._input)

        # make Heading objects and put them all in as roots to the Contents Tree.
        for i, heading_match in enumerate(headings_iterator):
            level = self.get_heading_level(heading_match.group(1))
            text = heading_match.group(2).rstrip()

            subheading = Heading(val=text, level=level, start=heading_match.start(), end=heading_match.end())
            self._contents_tree.add_subheading(subheading)

        if self._includes_title:
            self.title = self._contents_tree.subheadings[0]

        return
コード例 #5
0
ファイル: extra_buttons.py プロジェクト: wo4wangle/anki
def toggleHeading(self):
    selected = self.web.selectedText()
    Heading(self, self.parentWindow, selected)
コード例 #6
0
ファイル: trémaux_mouse.py プロジェクト: clarkbab/robomouse
    def plan_move(self, readings):
        # Get the ID of the current square.
        square_id = self.square_id(self.state.pos)

        # If it's our first move, mark the square as a node and pick an exit or
        # rotate.
        if self.initialising:
            self.initialising = False
            self.graph.add_node(square_id)
            self.last_node = square_id

            # Get all the exits.
            exits = np.nonzero(readings)[0]

            # If no exits, rotate.
            if len(exits) == 0:
                return -90, 0

            # Pick the first exit.
            sensor = Sensor(exits[0])
            rot = sensor.rotation()
            rot = Sensor.rotation(sensor)
            return rot, 1

        # Check if we should reset.
        if self.phase == Phase.PLAN and self.reached_goal:
            if self.verbose: print(f"[MOUSE] Finished planning.")

            # Begin execution phase.
            self.phase = Phase.EXECUTE
            self.state.reset()
            self.initialising = True
            self.graph = Graph()
            return 'RESET', 'RESET'

        # Check if we're backtracking.
        if self.backtrack:
            self.backtrack = False

            # Get the direction we're moving in.
            move_heading = self.state.heading.rotate(Rotation.LEFT)

            # Load up the edge we'll be travelling on.
            edge = self.graph.find_edge_by_heading(square_id, move_heading)

            # What's the largest move we can make down this edge?
            move = self.edge_move(edge)

            return Rotation.LEFT, move

        # If it's not a node, just move forward.
        if not self.node_sensed(readings):
            # Get the edge we're currently on.
            edge = self.graph.find_edge_by_heading(self.last_node, self.state.heading)

            # If we're on an edge, move further if possible.
            move = self.edge_move(edge) if edge else 1

            return Rotation.NONE, move
        
        # At this point we've decided that the square is a node.

        # Add the node if it hasn't been already.
        node_already_added = self.graph.node_added(square_id)
        if not node_already_added:
            # Add the node.
            self.graph.add_node(square_id)

        # We're turning around on the spot, don't need to add an edge.
        if square_id != self.last_node:
            # Check if edge already exists.
            if not self.graph.find_edge_by_nodes(self.last_node, square_id):
                # Get positions of nodes.
                node_pos1 = self.square_position(self.last_node)
                node_pos2 = self.square_position(square_id)

                # Get distance between nodes.
                vec = node_pos2 - node_pos1
                dist = int(np.linalg.norm(vec))

                # Get headings traversing from node 1 to 2, and reverse.
                head_vect = vec / dist 
                heading = Heading.from_components(head_vect)

                # Add the new edge.
                self.graph.add_edge(self.last_node, square_id, dist, heading)
            else:
                # Increment the number of traversals for this edge.
                self.graph.increment_traversal(self.last_node, square_id)

        # Get a prob for each direction.
        sensors = np.array([])
        weights = np.array([], dtype=np.float32)
        traversals = np.array([], dtype=np.int8)
        move_vecs = np.ndarray((0, 2), dtype=np.int8)
        for i, reading in enumerate(readings):
            # Don't consider the move if we'll hit a wall.
            if reading == 0: continue

            # Create the Sensor.
            sensor = Sensor(i)

            # Get the edge we'll be traversing if we take this move.
            sensor_heading = self.state.heading.rotate(sensor.rotation())
            edge = self.graph.find_edge_by_heading(square_id, sensor_heading)

            # Get number of traversals. 0 if edge isn't recorded.
            traversal = edge['traversals'] if edge else 0

            # Don't take the edge if we've been there twice already.
            if traversal == 2:
                continue

            # If we're on an edge, we can possibly move faster.
            move = self.edge_move(edge) if edge else 1

            # Get the move vector components.
            move_vec = move * sensor_heading.components()
            
            # Add the number of edge traversals.
            traversals = np.append(traversals, traversal)

            # Add the move vec and sensor ID.
            move_vecs = np.vstack((move_vecs, move_vec))
            sensors = np.append(sensors, sensor)

            # How much of this move is towards the centre?
            weight = np.dot(move_vec, self.unit_centre())
            weights = np.append(weights, weight)

        # If no possible moves, let's turn around.
        if len(move_vecs) == 0:
            self.last_node = square_id
            return Rotation.LEFT, 0

        # If we're not turning on the spot, and we've already seen the node.
        if self.last_node != square_id and node_already_added:
            # If we only traversed the last edge once, go back that way. We've
            # reached the end of a branch in our depth-first search algorithm.
            num_traversals = self.graph.find_edge_by_nodes(self.last_node, square_id)['traversals']
            if num_traversals == 1:
                self.last_node = square_id
                self.backtrack = True
                return Rotation.LEFT, 0

        # Take the road less travelled, i.e, select those squares that we've visited less.
        min_idx = np.argwhere(traversals == np.min(traversals)).flatten()

        # Only keep edges with minimum traversals.
        sensors = sensors[min_idx]
        weights = weights[min_idx]
        move_vecs = move_vecs[min_idx]

        # Apply the softmax function.
        probs = self.softmax(weights)
        
        # Get a sensor based on the probs.
        sensor = np.random.choice(sensors, p=probs)
        idx = np.where(sensors == sensor)[0][0]

        # Get the rotation and move to perform.
        rot = sensor.rotation()
        move_vec = move_vecs[idx]
        move = abs(move_vec).max()
        
        # Update internal state.
        self.last_node = square_id
        
        # The last thing we do is update our state. We don't know anything about
        # the next square at this point; this info will be handed to us with the
        # next sensor reading. So it doesn't make any sense to start working on
        # adding the next node or anything. In fact, we don't know if this step
        # will bring us to a node or a passage until we get sensor readings.

        return rot, move
コード例 #7
0
ファイル: prettymd.py プロジェクト: akashb95/prettymd-py
class PrettyMD:
    HEADING_LEVEL = Literal[1, 2, 3, 4, 5, 6]

    # Headings start with '#' chars, which can have upto 3 whitespaces before it.
    # Heading then needs to have some text after it that is not whitespace or #.
    HEADING_REGEX = re.compile(r'^_{,3}(#{1,6})\s*([^#].+)\s*', re.MULTILInseINE)

    BULLET_POINT_CHAR = "*"

    def __init__(self, original: str, includes_title: bool = False, link: bool = True, back_to_toc_link: bool = True):
        """

        :param original: Input Markdown text.
        :param includes_title: Whether a Title is included in the input text. If so, it'll be excluded from the ToC.
        :param link: Whether to include hyperlinks from the ToC to the relevant headings.
        :param back_to_toc_link: Whether to include hyperlinks at end of each section that navigates to the ToC.
        """

        self._input = original
        self._output = ""
        self._includes_title = includes_title
        self._link = link
        self._navlink = back_to_toc_link

        self.title = None

        # Root node of Contents
        self._contents_tree = Heading(val=None, level=-1, start=0, end=0, subheadings=None, height=-1)

        # table of contents - need to join with \n
        self._toc_items = ["<a name='nav'></a>\n## Contents 🗺"]

        # Updates self._contents_tree - adds all Headings as subheadings. Still a mostly-flat structure.
        self.parse_headings()

        # if MD includes title, then don't put title in ToC, and put ToC's location to begin after the title.
        if self._includes_title:
            all_headings = self._contents_tree.subheadings[1:]
            self._toc_location = self._contents_tree.subheadings[0].end
        else:
            all_headings = self._contents_tree
            self._toc_location = 0

        # Make Contents Tree from list of Headings. Unflattened structure.
        self._contents_tree.set_subheadings(self.construct_contents_tree(all_headings))

        # update self._toc_items
        self.make_toc()
        return

    def parse_headings(self) -> None:
        """
        Finds using RegEx the headings in :instance_attribute:`self._input`. Add all these headings to the root of the
        contents tree, that is the :instance_attribute:`self._contents_tree`.

        :return:
        """

        # find all headings by matching regex
        headings_iterator = re.finditer(self.HEADING_REGEX, self._input)

        # make Heading objects and put them all in as roots to the Contents Tree.
        for i, heading_match in enumerate(headings_iterator):
            level = self.get_heading_level(heading_match.group(1))
            text = heading_match.group(2).rstrip()

            subheading = Heading(val=text, level=level, start=heading_match.start(), end=heading_match.end())
            self._contents_tree.add_subheading(subheading)

        if self._includes_title:
            self.title = self._contents_tree.subheadings[0]

        return

    def make_toc(self) -> None:
        """
        Updates :instance_attribute:`self._toc_items` with text that represents the Table of Contents.

        :return:
        """

        # 1st element is the root of the graph, which is always going to have val=None
        flattened_toc = self.flatten_contents_tree(self._contents_tree)[1:]

        i = 0
        while i < len(flattened_toc):

            if self._link:
                toc_line = "[{}](#{})".format(flattened_toc[i].val, flattened_toc[i].anchor_name)
            else:
                toc_line = "{}".format(flattened_toc[i].val)

            self._toc_items.append("\t" * flattened_toc[i].height + "{} {}".format(self.BULLET_POINT_CHAR, toc_line))

            i += 1

        # if ToC lines to be linked to the Headings, insert the anchors.
        if self._link:
            self.insert_anchors(flattened_toc)
        else:
            self._output = self._input

        return

    def flatten_contents_tree(self, heading: Heading) -> List[Heading]:
        """
        In-order traversal of :instance_attribute:`self._contents_tree`

        :return:
        """

        flat_contents_tree = [
            Heading(val=heading.val, level=heading.level, height=heading.height, start=heading.start, end=heading.end)]

        if len(heading) == 0:
            return flat_contents_tree

        for subheading in heading.subheadings:
            flat_contents_tree.extend(self.flatten_contents_tree(subheading))

        return flat_contents_tree

    def insert_anchors(self, flattened_toc: List[Heading]) -> None:
        """
        Inserts the anchors before each of the headings.

        Updates :instance_attribute:`self._output`.

        :param flattened_toc:
        :return:
        """

        input_str_ptr = 0
        if self._includes_title:
            input_str_ptr = flattened_toc[0].end

        for heading in flattened_toc:

            # get anchor str e.g. <a name='#anchor'></a>
            anchor = heading.generate_anchor()

            navlink = ""
            if self._navlink:
                navlink = "\n[🗺 Go back to Navigation &uarr;‍](#nav)\n\n"

            # update _output string by inserting anchor before the heading text
            self._output += "{}\n{}{}\n{}" \
                .format(self._input[input_str_ptr:heading.start], navlink,
                        anchor, self._input[heading.start:heading.end])

            # update pointer in _input string
            input_str_ptr = heading.end

        self._output += self._input[input_str_ptr:] + "\n\n[🗺 Go back to Navigation &uarr;‍](#nav)\n"

        return

    @staticmethod
    def get_heading_level(heading: str) -> HEADING_LEVEL:
        return min(len(heading), 6)

    @staticmethod
    def construct_contents_tree(headings_list: List[Heading]) -> List[Heading]:
        """
        Constructs a Tree that represents the Contents from a flat List of :class:`Heading`.

        :param headings_list:
        :return:
        """

        if len(headings_list) == 0:
            return []

        # list of root Headings
        graph = []
        lowest_level = headings_list[0].level

        for i, heading in enumerate(headings_list):
            if heading.level <= lowest_level:

                if heading.level < lowest_level:
                    lowest_level = heading.level

                graph.append(heading)

            else:
                subheading = Heading(heading.val, heading.level, heading.start, heading.end)
                graph[-1].add_subheading(subheading)

        for heading in graph:
            subheadings = PrettyMD.construct_contents_tree(heading.subheadings)
            heading.set_subheadings(subheadings)

        return graph

    @property
    def toc(self):
        return "\n".join(self._toc_items)

    @property
    def output(self):
        title = ""
        if self.title is not None:
            title = self._input[:self.title.end]

        return "{title}\n{contents}{body}".format(title=title, contents=self.toc, body=self._output)
コード例 #8
0
 def _start_heading(self):
     return Heading(shared_vars['start_heading'].get())
コード例 #9
0
 def _desired_heading(self):
     return Heading(shared_vars['desired_heading'].get())
コード例 #10
0
 def _heading(self):
     return Heading(shared_vars['heading'].get())
コード例 #11
0
def toggle_heading(editor):
    selected = editor.web.selectedText()
    Heading(editor, editor.parentWindow, selected)