nu-cli/completions: add completion for $env. (#5199)

* nu-cli/completions: add completion for $env.

* use stack to avoid showing hidden env vars
This commit is contained in:
Herlon Aguiar 2022-04-15 15:17:53 +02:00 committed by GitHub
parent 583b7b1821
commit 2a3991cfdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 6 deletions

View File

@ -8,6 +8,7 @@ use nu_protocol::{
Span, Value,
};
use reedline::{Completer as ReedlineCompleter, Suggestion};
use std::str;
use std::sync::Arc;
#[derive(Clone)]
@ -69,6 +70,10 @@ impl NuCompleter {
for (flat_idx, flat) in flattened.iter().enumerate() {
if pos >= flat.0.start && pos < flat.0.end {
// Context variables
let mut is_variable_completion = false;
let mut previous_expr: Vec<u8> = vec![];
// Create a new span
let new_span = Span {
start: flat.0.start,
@ -79,9 +84,32 @@ impl NuCompleter {
let mut prefix = working_set.get_span_contents(flat.0).to_vec();
prefix.remove(pos - flat.0.start);
// Try to get the previous expression
if flat_idx > 0 {
match flattened.get(flat_idx - 1) {
Some(value) => {
let previous_prefix =
working_set.get_span_contents(value.0).to_vec();
// Update the previous expression
previous_expr = previous_prefix;
// Check if should match variable completion
if matches!(value.1, FlatShape::Variable) {
is_variable_completion = true;
}
}
None => {}
}
}
// Variables completion
if prefix.starts_with(b"$") {
let mut completer = VariableCompletion::new(self.engine_state.clone());
if prefix.starts_with(b"$") || is_variable_completion {
let mut completer = VariableCompletion::new(
self.engine_state.clone(),
self.stack.clone(),
previous_expr,
);
return self.process_completion(
&mut completer,

View File

@ -1,6 +1,6 @@
use crate::completions::{Completer, CompletionOptions};
use nu_protocol::{
engine::{EngineState, StateWorkingSet},
engine::{EngineState, Stack, StateWorkingSet},
Span,
};
use reedline::Suggestion;
@ -9,11 +9,17 @@ use std::sync::Arc;
#[derive(Clone)]
pub struct VariableCompletion {
engine_state: Arc<EngineState>,
stack: Stack,
previous_expr: Vec<u8>,
}
impl VariableCompletion {
pub fn new(engine_state: Arc<EngineState>) -> Self {
Self { engine_state }
pub fn new(engine_state: Arc<EngineState>, stack: Stack, previous_expr: Vec<u8>) -> Self {
Self {
engine_state,
stack,
previous_expr,
}
}
}
@ -27,10 +33,30 @@ impl Completer for VariableCompletion {
_: usize,
) -> (Vec<Suggestion>, CompletionOptions) {
let mut output = vec![];
let builtins = ["$nu", "$in", "$config", "$env", "$nothing"];
let previous_expr_str = std::str::from_utf8(&self.previous_expr)
.unwrap_or("")
.to_lowercase();
// Completions for the given variable (e.g: $env.<tab> for completing $env.SOMETHING)
if !self.previous_expr.is_empty() && previous_expr_str.as_str() == "$env" {
for env_var in self.stack.get_env_vars(&self.engine_state) {
output.push(Suggestion {
value: env_var.0,
description: None,
extra: None,
span: reedline::Span {
start: span.start - offset,
end: span.end - offset,
},
});
}
return (output, CompletionOptions::default());
}
for builtin in builtins {
// Variable completion (e.g: $en<tab> to complete $env)
if builtin.as_bytes().starts_with(&prefix) {
output.push(Suggestion {
value: builtin.to_string(),
@ -44,6 +70,7 @@ impl Completer for VariableCompletion {
}
}
// Working set scope vars
for scope in &working_set.delta.scope {
for v in &scope.vars {
if v.0.starts_with(&prefix) {
@ -59,6 +86,8 @@ impl Completer for VariableCompletion {
}
}
}
// Permanent state vars
for scope in &self.engine_state.scope {
for v in &scope.vars {
if v.0.starts_with(&prefix) {

View File

@ -1233,6 +1233,16 @@ impl<'a> StateWorkingSet<'a> {
self.permanent_state.env_vars.get(name)
}
pub fn list_env(&self) -> Vec<String> {
let mut env_vars = vec![];
for env_var in self.permanent_state.env_vars.clone().into_iter() {
env_vars.push(env_var.0)
}
env_vars
}
pub fn set_variable_type(&mut self, var_id: VarId, ty: Type) {
let num_permanent_vars = self.permanent_state.num_vars();
if var_id < num_permanent_vars {