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
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()
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()
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
def test_cursor_in_same_position(view_a, view_b, expected): assert cursor_in_same_position(view_a, view_b) is expected
def is_target(self): return cursor_in_same_position(self.view, self.dijkstra.target_view)