def autorun():
    """Called on a timer several times per second, if autorun is enabled."""
    global start_state, current_state
    new_state = RecordedState()

    if (
        current_state.mode in ["n", "v", "V"]
        and time.time() >= current_state.time + vim.vars["pf_autorun_delay"]
        # This is checked in run(), but that would reset the timer if we called it
        and not cursor_in_same_position(start_state.view, current_state.view)
    ):
        # No motions for the configured timeout
        run()
    elif start_state.mode != new_state.mode:
        if start_state.mode in ["n", "v", "V"]:
            # Changed modes, leaving one of normal, visual or visual-line
            # (we don't want to trigger for leaving e.g. insert mode since cursor
            # movements there are not made with motions)
            run()
        else:
            reset()
    elif (
        new_state.mode == "n"
        and new_state.buffer_contents != start_state.buffer_contents
    ):
        # Buffer has changed in normal mode
        # This means a command like x,rx,p must have been used
        run()
    elif not cursor_in_same_position(current_state.view, new_state.view):
        current_state = new_state
    def find_path(self, client_connection, min_line, max_line):
        """
        Use Dijkstra's algorithm to find the optimal sequence of motions.

        :param client_connection: If another pathfinding request is waiting on this
            connection, exit (returning None) as soon as possible. This cancels the
            pathfinding, moving on to the new request immediately.
        :param min_line: Do not explore above this line number.
        :param max_line: Do not explore below this line number.
        """
        while len(self._open_nodes) > 0 and not client_connection.poll():
            self._current_node, self._current_g = self._open_nodes.popitem()

            if cursor_in_same_position(self._current_node.view,
                                       self.target_view):
                # We found the target!
                return self._current_node.get_refined_path()

            for motion in self.available_motions:
                child_view = self._current_node.test_motion(motion)
                if (child_view is not None
                        and int(child_view["lnum"]) >= min_line
                        and int(child_view["lnum"]) <= max_line):
                    try:
                        # Add a connection from self._current_node to the node
                        # associated with the child view.
                        # This will either replace the existing path into the node,
                        # add the motion as an alternative, or create a new node if
                        # one did not already exist.
                        self._add_connection(child_view, motion)
                    except NodeClosed:
                        pass
Example #3
0
 def autorun(self):
     """Called on a timer several times per second."""
     if self.state_tracker.choose_action_using(choose_action) == "pathfind":
         if not cursor_in_same_position(
             self.state_tracker.start_state.view,
             self.state_tracker.target_state.view,
         ):
             self._run()
         self.state_tracker.reset()
Example #4
0
    def command_run(self):
        """Called for the :PathfinderRun command."""
        self.state_tracker.set_target()

        if cursor_in_same_position(
            self.state_tracker.start_state.view,
            self.state_tracker.target_state.view,
        ):
            print("You must move the cursor to a new location first!")
        else:
            self._run()
def run():
    """
    Start calculating a path.

    This is called by loop() below, when there are no motions for a while. It also
    runs for a variety of autocmd events which indicate the end of a movement, such as
    entering insert mode.
    """
    if start_state is None or current_state is None:
        return

    if not cursor_in_same_position(start_state.view, current_state.view):
        # Start pathfinding in the background and call display_results when done
        client.pathfind(start_state.view, current_state.view, show_output)

    reset()
Example #6
0
    def test_motion(self, motion):
        """
        Attempt to run the given motion from this node's position within Vim.

        :returns: New view, if the motion moved the cursor to another position and did
            not cause an error. Otherwise None.
        """
        winrestview(self.view)
        try:
            # `execute` is required to use motions like <C-f>
            vim.command(f'execute "silent! normal! {motion.motion}"')
        except vim.error:
            # Ignore motions which fail
            return

        new_view = winsaveview()
        if not cursor_in_same_position(new_view, self.view):
            # The cursor has moved, return the newly created node
            return new_view
Example #7
0
def test_cursor_in_same_position(view_a, view_b, expected):
    assert cursor_in_same_position(view_a, view_b) is expected
Example #8
0
 def is_target(self):
     return cursor_in_same_position(self.view, self.dijkstra.target_view)