Working markers

This commit is contained in:
2026-06-21 23:37:50 +02:00
parent 5054185e0d
commit 173c983c6f
+45 -15
View File
@@ -80,16 +80,48 @@ fn byte_offset_from_lsp(source: &str, line: u32, character: u32) -> Option<usize
} }
} }
/// Back up to the start of the current identifier/word so the marker isn't /// Inject a marker at the exact cursor position. If the cursor is inside or
/// injected in the middle of a token (which would break parsing). /// at the start of an identifier-like token, the entire token is replaced with
fn snap_to_word_start(source: &str, offset: usize) -> usize { /// the marker so parsing doesn't break from a mid-token split.
fn inject_marker_at(source: &str, line: u32, character: u32, marker: &str) -> Option<String> {
let offset = byte_offset_from_lsp(source, line, character)?;
let before = &source[..offset]; let before = &source[..offset];
let trim = before let after = &source[offset..];
// Identifier chars immediately before and after the cursor (as byte-counts).
let trail_bytes: usize = before
.chars() .chars()
.rev() .rev()
.take_while(|c| c.is_alphanumeric() || *c == '_') .take_while(|c| c.is_alphanumeric() || *c == '_')
.count(); .map(|c| c.len_utf8())
offset - trim .sum();
let lead_bytes: usize = after
.chars()
.take_while(|c| c.is_alphanumeric() || *c == '_')
.map(|c| c.len_utf8())
.sum();
if trail_bytes > 0 || lead_bytes > 0 {
// Cursor touches an identifier — replace the whole token with the marker.
let token_start = offset - trail_bytes;
let token_end = offset + lead_bytes;
let mut s = String::with_capacity(source.len() + marker.len() + 4);
s.push_str(&source[..token_start]);
s.push_str(marker);
s.push_str(&source[token_end..]);
Some(s)
} else {
// Cursor is on whitespace / punctuation — inject as standalone expression.
let mut s = String::with_capacity(source.len() + marker.len() + 4);
s.push_str(&source[..offset]);
s.push(' ');
s.push_str(marker);
s.push(' ');
s.push_str(&source[offset..]);
Some(s)
}
} }
fn find_marker_position(content: &str, marker: &str) -> Option<Position> { fn find_marker_position(content: &str, marker: &str) -> Option<Position> {
@@ -160,15 +192,13 @@ impl Backend {
let id = MARKER_COUNTER.fetch_add(1, Ordering::Relaxed); let id = MARKER_COUNTER.fetch_add(1, Ordering::Relaxed);
let marker = format!("__mist_mk{id:x}__"); let marker = format!("__mist_mk{id:x}__");
let offset = byte_offset_from_lsp(source, line, character)?; let modified = match inject_marker_at(source, line, character, &marker) {
let offset = snap_to_word_start(source, offset); Some(m) => m,
None => {
let mut modified = String::with_capacity(source.len() + marker.len() + 4); eprintln!("[marker] inject_marker_at returned None for LSP({line},{character})");
modified.push_str(&source[..offset]); return None;
modified.push(' '); }
modified.push_str(&marker); };
modified.push(' ');
modified.push_str(&source[offset..]);
let transpiled = match transpile_mist(mist_path, &modified, extra_mod_decl) { let transpiled = match transpile_mist(mist_path, &modified, extra_mod_decl) {
Ok(t) => t, Ok(t) => t,