nushell on your web browser
nushell wasm terminal
at main 2.9 kB view raw
1use crate::console_log; 2use futures::FutureExt; 3use js_sys::Promise; 4use nu_parser::{flatten_block, parse}; 5use nu_protocol::engine::StateWorkingSet; 6use wasm_bindgen::prelude::*; 7use wasm_bindgen_futures::future_to_promise; 8 9use super::*; 10 11pub mod context; 12pub mod helpers; 13pub mod suggestions; 14pub mod types; 15pub mod variables; 16 17pub use context::determine_context; 18pub use suggestions::generate_suggestions; 19pub use types::{CompletionContext, Suggestion}; 20 21#[wasm_bindgen] 22pub fn completion(input: String, js_cursor_pos: usize) -> Promise { 23 future_to_promise(completion_impl(input, js_cursor_pos).map(|s| Ok(JsValue::from_str(&s)))) 24} 25 26pub async fn completion_impl(input: String, js_cursor_pos: usize) -> String { 27 let engine_guard = read_engine_state().await; 28 let stack_guard = crate::read_stack().await; 29 let root = get_pwd(); 30 31 // Map UTF-16 cursor position (from JS) to Byte index (for Rust) 32 let byte_pos = input 33 .char_indices() 34 .map(|(i, _)| i) 35 .nth(js_cursor_pos) 36 .unwrap_or(input.len()); 37 38 let (working_set, shapes, global_offset) = { 39 let mut working_set = StateWorkingSet::new(&engine_guard); 40 let global_offset = working_set.next_span_start(); 41 let block = parse(&mut working_set, None, input.as_bytes(), false); 42 let shapes = flatten_block(&working_set, &block); 43 (working_set, shapes, global_offset) 44 }; 45 46 // Initial state logging 47 console_log!( 48 "[completion] Input: {input:?}, JS cursor: {js_cursor_pos}, byte cursor: {byte_pos}" 49 ); 50 console_log!( 51 "[completion] Found {count} shapes, global_offset: {global_offset}", 52 count = shapes.len() 53 ); 54 for (idx, (span, shape)) in shapes.iter().enumerate() { 55 let (local_start, local_end) = ( 56 span.start.saturating_sub(global_offset), 57 span.end.saturating_sub(global_offset), 58 ); 59 console_log!( 60 "[completion] Shape {idx}: {shape:?} at [{start}, {end}] (local: [{local_start}, {local_end}])", 61 start = span.start, 62 end = span.end 63 ); 64 } 65 66 // Determine completion context 67 let context = determine_context( 68 &input, 69 &shapes, 70 &working_set, 71 &engine_guard, 72 byte_pos, 73 global_offset, 74 ); 75 76 // Convert Vec to HashSet 77 use std::collections::HashSet; 78 let context_set: HashSet<CompletionContext> = context.into_iter().collect(); 79 80 // Generate suggestions based on context 81 let suggestions = generate_suggestions( 82 &input, 83 context_set, 84 &working_set, 85 &engine_guard, 86 &stack_guard, 87 &root, 88 byte_pos, 89 ); 90 91 drop(working_set); 92 drop(engine_guard); 93 94 let suggestions = serde_json::to_string(&suggestions).unwrap_or_else(|_| "[]".to_string()); 95 console_log!("{suggestions}"); 96 suggestions 97}