Fix bug in cursor
This commit is contained in:
parent
bd75161e86
commit
f2bd8fee97
5 changed files with 99 additions and 19 deletions
|
@ -24,8 +24,6 @@ downcast-rs = "1.2.1"
|
||||||
getopts = "0.2.21"
|
getopts = "0.2.21"
|
||||||
graphviz-rust = "0.9.0"
|
graphviz-rust = "0.9.0"
|
||||||
lazy_static = "1.5.0"
|
lazy_static = "1.5.0"
|
||||||
lsp-server = "0.7.6"
|
|
||||||
lsp-types = "0.97.0"
|
|
||||||
mlua = { version = "0.9.9", features = ["lua54", "vendored", "serialize"] }
|
mlua = { version = "0.9.9", features = ["lua54", "vendored", "serialize"] }
|
||||||
regex = "1.10.3"
|
regex = "1.10.3"
|
||||||
rusqlite = "0.31.0"
|
rusqlite = "0.31.0"
|
||||||
|
@ -38,7 +36,6 @@ tokio = { version = "1.38.1", features = [
|
||||||
"rt-multi-thread",
|
"rt-multi-thread",
|
||||||
"io-std",
|
"io-std",
|
||||||
] }
|
] }
|
||||||
|
|
||||||
tower-lsp = "0.20.0"
|
tower-lsp = "0.20.0"
|
||||||
unicode-segmentation = "1.11.0"
|
unicode-segmentation = "1.11.0"
|
||||||
walkdir = "2.5.0"
|
walkdir = "2.5.0"
|
||||||
|
|
|
@ -455,7 +455,7 @@ mod tests {
|
||||||
use crate::parser::langparser::LangParser;
|
use crate::parser::langparser::LangParser;
|
||||||
use crate::parser::parser::Parser;
|
use crate::parser::parser::Parser;
|
||||||
use crate::parser::source::SourceFile;
|
use crate::parser::source::SourceFile;
|
||||||
use crate::validate_document;
|
use crate::{validate_document, validate_semantics};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -555,13 +555,29 @@ nml.section.push("6", 6, "", "refname")
|
||||||
let source = Rc::new(SourceFile::with_content(
|
let source = Rc::new(SourceFile::with_content(
|
||||||
"".to_string(),
|
"".to_string(),
|
||||||
r#"
|
r#"
|
||||||
#{か} test
|
# First section
|
||||||
|
##{か}+ test
|
||||||
|
#{refname}*+ Another section
|
||||||
"#
|
"#
|
||||||
.to_string(),
|
.to_string(),
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
let parser = LangParser::default();
|
let parser = LangParser::default();
|
||||||
let (_, state) = parser.parse(ParserState::new_with_semantics(&parser, None), source, None);
|
let (_, state) = parser.parse(ParserState::new_with_semantics(&parser, None), source.clone(), None);
|
||||||
println!("{:#?}", state.shared.semantics);
|
|
||||||
|
validate_semantics!(state, source.clone(), 0,
|
||||||
|
section_heading { delta_line == 1, delta_start == 0, length == 1 };
|
||||||
|
section_name { delta_line == 0, delta_start == 1 };
|
||||||
|
|
||||||
|
section_heading { delta_line == 1, delta_start == 0, length == 2 };
|
||||||
|
section_reference { delta_line == 0, delta_start == 2, length == 3 };
|
||||||
|
section_kind { delta_line == 0, delta_start == 3, length == 1 };
|
||||||
|
section_name { delta_line == 0, delta_start == 1 };
|
||||||
|
|
||||||
|
section_heading { delta_line == 1, delta_start == 0, length == 1 };
|
||||||
|
section_reference { delta_line == 0, delta_start == 1, length == 9 };
|
||||||
|
section_kind { delta_line == 0, delta_start == 9, length == 2 };
|
||||||
|
section_name { delta_line == 0, delta_start == 2 };
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use std::any::Any;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -143,6 +142,9 @@ impl Semantics {
|
||||||
.find('\n')
|
.find('\n')
|
||||||
.unwrap_or(source.content().len() - cursor.pos);
|
.unwrap_or(source.content().len() - cursor.pos);
|
||||||
let len = usize::min(range.end - cursor.pos, end);
|
let len = usize::min(range.end - cursor.pos, end);
|
||||||
|
let clen = source.content()[cursor.pos..cursor.pos+len]
|
||||||
|
.chars()
|
||||||
|
.fold(0, |clen, _| clen + 1);
|
||||||
|
|
||||||
let delta_line = cursor.line - current.line;
|
let delta_line = cursor.line - current.line;
|
||||||
let delta_start = if delta_line == 0 {
|
let delta_start = if delta_line == 0 {
|
||||||
|
@ -159,7 +161,7 @@ impl Semantics {
|
||||||
tokens.push(SemanticToken {
|
tokens.push(SemanticToken {
|
||||||
delta_line: delta_line as u32,
|
delta_line: delta_line as u32,
|
||||||
delta_start: delta_start as u32,
|
delta_start: delta_start as u32,
|
||||||
length: len as u32,
|
length: clen as u32,
|
||||||
token_type: token.0,
|
token_type: token.0,
|
||||||
token_modifiers_bitset: token.1
|
token_modifiers_bitset: token.1
|
||||||
});
|
});
|
||||||
|
@ -169,3 +171,72 @@ impl Semantics {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests {
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! validate_semantics {
|
||||||
|
($state:expr, $source:expr, $idx:expr,) => {};
|
||||||
|
($state:expr, $source:expr, $idx:expr, $token_name:ident { $($field:ident == $value:expr),* }; $($tail:tt)*) => {{
|
||||||
|
let token = $state.shared.semantics
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.get(&($source as Rc<dyn Source>))
|
||||||
|
.unwrap()
|
||||||
|
.tokens
|
||||||
|
.borrow()
|
||||||
|
[$idx];
|
||||||
|
let token_type = $state.shared.semantics
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.get(&($source as Rc<dyn Source>))
|
||||||
|
.unwrap()
|
||||||
|
.token
|
||||||
|
.$token_name;
|
||||||
|
|
||||||
|
|
||||||
|
let found_token = (token.token_type, token.token_modifiers_bitset);
|
||||||
|
assert!(found_token == token_type, "Invalid token at index {}, expected {}{token_type:#?}, got: {found_token:#?}",
|
||||||
|
$idx, stringify!($token_name));
|
||||||
|
|
||||||
|
$(
|
||||||
|
let val = &token.$field;
|
||||||
|
assert!(*val == $value, "Invalid field {} at index {}, expected {:#?}, found {:#?}",
|
||||||
|
stringify!($field),
|
||||||
|
$idx,
|
||||||
|
$value,
|
||||||
|
val);
|
||||||
|
)*
|
||||||
|
|
||||||
|
validate_semantics!($state, $source, ($idx+1), $($tail)*);
|
||||||
|
}};
|
||||||
|
($state:expr, $source:expr, $idx:expr, $token_name:ident; $($tail:tt)*) => {{
|
||||||
|
let token = $state.shared.semantics
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.get(&($source as Rc<dyn Source>))
|
||||||
|
.unwrap()
|
||||||
|
.tokens
|
||||||
|
.borrow()
|
||||||
|
[$idx];
|
||||||
|
let token_type = $state.shared.semantics
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.get(&($source as Rc<dyn Source>))
|
||||||
|
.unwrap()
|
||||||
|
.token
|
||||||
|
.$token_name;
|
||||||
|
|
||||||
|
|
||||||
|
let found_token = (token.token_type, token.token_modifiers_bitset);
|
||||||
|
assert!(found_token == token_type, "Invalid token at index {}, expected {}{token_type:#?}, got: {found_token:#?}",
|
||||||
|
$idx, stringify!($token_name));
|
||||||
|
|
||||||
|
validate_semantics!($state, $source, ($idx+1), $($tail)*);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use std::rc::Rc;
|
||||||
|
|
||||||
use downcast_rs::impl_downcast;
|
use downcast_rs::impl_downcast;
|
||||||
use downcast_rs::Downcast;
|
use downcast_rs::Downcast;
|
||||||
use unicode_width::UnicodeWidthChar;
|
|
||||||
|
|
||||||
/// Trait for source content
|
/// Trait for source content
|
||||||
pub trait Source: Downcast {
|
pub trait Source: Downcast {
|
||||||
|
@ -153,9 +152,13 @@ impl Clone for Cursor {
|
||||||
/// Cursor type used for the language server
|
/// Cursor type used for the language server
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LineCursor {
|
pub struct LineCursor {
|
||||||
|
/// Byte position in the source
|
||||||
pub pos: usize,
|
pub pos: usize,
|
||||||
|
/// Line number
|
||||||
pub line: usize,
|
pub line: usize,
|
||||||
|
/// Position in the line
|
||||||
pub line_pos: usize,
|
pub line_pos: usize,
|
||||||
|
/// Source
|
||||||
pub source: Rc<dyn Source>,
|
pub source: Rc<dyn Source>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,14 +174,13 @@ impl LineCursor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves [`LineCursor`] to absolute position
|
/// Moves [`LineCursor`] to an absolute byte position
|
||||||
///
|
///
|
||||||
/// # Error
|
/// # Error
|
||||||
/// This function will panic if [`pos`] is not utf8 aligned
|
/// This function will panic if [`pos`] is not utf8 aligned
|
||||||
pub fn move_to(&mut self, pos: usize) {
|
pub fn move_to(&mut self, pos: usize) {
|
||||||
if self.pos < pos {
|
if self.pos < pos {
|
||||||
let start = self.pos;
|
let start = self.pos;
|
||||||
//eprintln!("slice{{{}}}, want={pos}", &self.source.content().as_str()[start..pos]);
|
|
||||||
let mut it = self.source.content().as_str()[start..] // pos+1
|
let mut it = self.source.content().as_str()[start..] // pos+1
|
||||||
.chars()
|
.chars()
|
||||||
.peekable();
|
.peekable();
|
||||||
|
@ -187,7 +189,6 @@ impl LineCursor {
|
||||||
.chars()
|
.chars()
|
||||||
.rev()
|
.rev()
|
||||||
.next();
|
.next();
|
||||||
//eprintln!("prev={prev:#?}");
|
|
||||||
while self.pos < pos {
|
while self.pos < pos {
|
||||||
let c = it.next().unwrap();
|
let c = it.next().unwrap();
|
||||||
let len = c.len_utf8();
|
let len = c.len_utf8();
|
||||||
|
@ -196,10 +197,8 @@ impl LineCursor {
|
||||||
self.line += 1;
|
self.line += 1;
|
||||||
self.line_pos = 0;
|
self.line_pos = 0;
|
||||||
}
|
}
|
||||||
self.line_pos += c.width().unwrap_or(1);
|
self.line_pos += 1;
|
||||||
self.pos += len;
|
self.pos += len;
|
||||||
|
|
||||||
//eprintln!("({}, {c:#?}, {} {}, {})", self.pos, self.line, self.line_pos, prev.unwrap_or(' '));
|
|
||||||
prev = Some(c);
|
prev = Some(c);
|
||||||
}
|
}
|
||||||
if self.pos != 0 && prev == Some('\n') {
|
if self.pos != 0 && prev == Some('\n') {
|
||||||
|
|
|
@ -9,7 +9,6 @@ mod parser;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use lsp::semantic::Tokens;
|
|
||||||
use parser::langparser::LangParser;
|
use parser::langparser::LangParser;
|
||||||
use parser::parser::Parser;
|
use parser::parser::Parser;
|
||||||
use parser::parser::ParserState;
|
use parser::parser::ParserState;
|
||||||
|
@ -25,8 +24,6 @@ use tower_lsp::Server;
|
||||||
struct Backend {
|
struct Backend {
|
||||||
client: Client,
|
client: Client,
|
||||||
document_map: DashMap<String, String>,
|
document_map: DashMap<String, String>,
|
||||||
//ast_map: DashMap<String, Vec<Box<dyn Element>>>,
|
|
||||||
//variables: DashMap<String, HashMap<String, Arc<dyn Variable + Send + Sync + 'static>>>,
|
|
||||||
semantic_token_map: DashMap<String, Vec<SemanticToken>>,
|
semantic_token_map: DashMap<String, Vec<SemanticToken>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue