nu-cli/completions: cache layer for fetching (#5114)

This commit is contained in:
Herlon Aguiar 2022-04-07 21:36:16 +02:00 committed by GitHub
parent 5e177fe8e7
commit e86c1b118e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 16 deletions

View file

@ -9,20 +9,20 @@ use nu_protocol::{
use reedline::Suggestion; use reedline::Suggestion;
use std::sync::Arc; use std::sync::Arc;
pub struct CommandCompletion { pub struct CommandCompletion<'a> {
engine_state: Arc<EngineState>, engine_state: Arc<EngineState>,
flattened: Vec<(Span, FlatShape)>, flattened: &'a [(Span, FlatShape)],
flat_idx: usize, flat_idx: usize,
flat_shape: FlatShape, flat_shape: &'a FlatShape,
} }
impl CommandCompletion { impl<'a> CommandCompletion<'a> {
pub fn new( pub fn new(
engine_state: Arc<EngineState>, engine_state: Arc<EngineState>,
_: &StateWorkingSet, _: &StateWorkingSet,
flattened: Vec<(Span, FlatShape)>, flattened: &'a [(Span, FlatShape)],
flat_idx: usize, flat_idx: usize,
flat_shape: FlatShape, flat_shape: &'a FlatShape,
) -> Self { ) -> Self {
Self { Self {
engine_state, engine_state,
@ -146,7 +146,7 @@ impl CommandCompletion {
} }
} }
impl Completer for CommandCompletion { impl<'a> Completer for CommandCompletion<'a> {
fn fetch( fn fetch(
&mut self, &mut self,
working_set: &StateWorkingSet, working_set: &StateWorkingSet,

View file

@ -1,20 +1,23 @@
use crate::completions::{ use crate::completions::{
CommandCompletion, Completer, CustomCompletion, FileCompletion, FlagCompletion, CommandCompletion, Completer, CompletionOptions, CustomCompletion, FileCompletion,
VariableCompletion, FlagCompletion, VariableCompletion,
}; };
use nu_parser::{flatten_expression, parse, FlatShape}; use nu_parser::{flatten_expression, parse, FlatShape};
use nu_protocol::{ use nu_protocol::{
engine::{EngineState, Stack, StateWorkingSet}, engine::{EngineState, Stack, StateWorkingSet},
Span, Value, Span, Value,
}; };
use reedline::{Completer as ReedlineCompleter, Suggestion}; use reedline::{Completer as ReedlineCompleter, Span as ReedlineSpan, Suggestion};
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant};
#[derive(Clone)] #[derive(Clone)]
pub struct NuCompleter { pub struct NuCompleter {
engine_state: Arc<EngineState>, engine_state: Arc<EngineState>,
stack: Stack, stack: Stack,
config: Option<Value>, config: Option<Value>,
cached_results: Option<(Vec<Suggestion>, CompletionOptions)>,
last_fetch: Option<Instant>,
} }
impl NuCompleter { impl NuCompleter {
@ -23,12 +26,14 @@ impl NuCompleter {
engine_state, engine_state,
stack, stack,
config, config,
cached_results: None,
last_fetch: None,
} }
} }
// Process the completion for a given completer // Process the completion for a given completer
fn process_completion<T: Completer>( fn process_completion<T: Completer>(
&self, &mut self,
completer: &mut T, completer: &mut T,
working_set: &StateWorkingSet, working_set: &StateWorkingSet,
prefix: Vec<u8>, prefix: Vec<u8>,
@ -36,9 +41,41 @@ impl NuCompleter {
offset: usize, offset: usize,
pos: usize, pos: usize,
) -> Vec<Suggestion> { ) -> Vec<Suggestion> {
// Cleanup the result cache if it's old
if let Some(instant) = self.last_fetch {
if instant.elapsed() > Duration::from_millis(1000) {
self.cached_results = None;
}
}
// Fetch // Fetch
let (mut suggestions, options) = let (mut suggestions, options) = match self.cached_results.clone() {
completer.fetch(working_set, prefix.clone(), new_span, offset, pos); Some((suggestions, options)) => {
// Update cached spans
let suggestions = suggestions
.into_iter()
.map(|suggestion| Suggestion {
value: suggestion.value,
description: suggestion.description,
extra: suggestion.extra,
span: ReedlineSpan {
start: new_span.start - offset,
end: new_span.end - offset,
},
})
.collect();
(suggestions, options)
}
None => {
let result = completer.fetch(working_set, prefix.clone(), new_span, offset, pos);
// Update cache results
self.cached_results = Some(result.clone());
result
}
};
// Filter // Filter
suggestions = completer.filter(prefix.clone(), suggestions, options.clone()); suggestions = completer.filter(prefix.clone(), suggestions, options.clone());
@ -46,11 +83,15 @@ impl NuCompleter {
// Sort // Sort
suggestions = completer.sort(suggestions, prefix, options); suggestions = completer.sort(suggestions, prefix, options);
// Update last fetch
self.last_fetch = Some(Instant::now());
suggestions suggestions
} }
fn completion_helper(&mut self, line: &str, pos: usize) -> Vec<Suggestion> { fn completion_helper(&mut self, line: &str, pos: usize) -> Vec<Suggestion> {
let mut working_set = StateWorkingSet::new(&self.engine_state); let engine_state = self.engine_state.clone();
let mut working_set = StateWorkingSet::new(&engine_state);
let offset = working_set.next_span_start(); let offset = working_set.next_span_start();
let mut line = line.to_string(); let mut line = line.to_string();
line.insert(pos, 'a'); line.insert(pos, 'a');
@ -143,9 +184,9 @@ impl NuCompleter {
let mut completer = CommandCompletion::new( let mut completer = CommandCompletion::new(
self.engine_state.clone(), self.engine_state.clone(),
&working_set, &working_set,
flattened.clone(), &flattened,
flat_idx, flat_idx,
flat_shape.clone(), flat_shape,
); );
return self.process_completion( return self.process_completion(