fst icon indicating copy to clipboard operation
fst copied to clipboard

Add next_start_node function to Stream

Open StratusFearMe21 opened this issue 1 year ago • 0 comments

What is this?

This adds a function to the Stream trait that allows you to see the current node that the dyn Stream will start from on the next call to Stream::next.

My use case

I'm trying to use an fst to implement auto-completion in a file dialog. Basically, I put all the files and directories into an fst, then I traverse the fst to the current partial file/folder name, then based on if the node I end up on has only 1 transition or not, I decide to either partially, or completely, complete the file or directory that the user is looking for, if that condition is true. 20230414_17h37m23s_grim Or display a tooltip with the possible files/directories, if that condition is false 20230414_17h33m43s_grim In order to do this, I need to traverse the fst to find the node to check for transitions on, then I need to traverse it again to initialize the searching stream for the tooltip, which isn't ideal.

let mut node = self.root();

for &b in key {
    node = match node.find_input(b) {
        None => return false,
        Some(i) => self.node(node.transition_addr(i)),
    }
}

if !node.is_final() {
    if node.transitions().count() == 1 {
       /* Complete file name */
       while node.transitions().count() == 1 {
         let t = node.transitions().next().unwrap();
         self.path_edit.push(t.inp as char);
         node = self.completion.machine.node(t.addr);
       }
    } else {
       let matcher = fst::automaton::Str::new(file_name).starts_with();
       let mut stream = self
         .completion
         .machine
         .search(matcher)
         .gt(file_name)
         .into_stream();
        /* Traverse stream to display tooltip */
    }
}

What this PR does, is it allows you to just initialize the stream from the get-go, and then call next_start_node to find where we end up after initializing the stream with a range

let matcher = fst::automaton::Str::new(file_name).starts_with();
let mut stream = self
  .completion
  .machine
  .search(matcher)
  .gt(file_name)
  .into_stream();

if let Some(mut node) = stream.next_start_node() {
  if node.transitions().count() == 1 {
     /* Complete file name */
     while node.transitions().count() == 1 {
       let t = node.transitions().next().unwrap();
       self.path_edit.push(t.inp as char);
       node = self.completion.machine.node(t.addr);
     }
  } else {
    /* Traverse stream to display tooltip */
  }
}

This way, I only have to traverse the fst once, for both cases. And I don't have to start over for the tooltip case.

StratusFearMe21 avatar Apr 14 '23 21:04 StratusFearMe21