use crate::core::*;
use log::info;
use ropey::Rope;
use std::borrow::Cow;
use std::cell::RefCell;
use tokio::time::Instant;
use tree_sitter::*;
use ustr::Ustr;
thread_local! {
static PARSER_UVL:RefCell<Parser> = RefCell::new(Parser::new());
static PARSER_JSON:RefCell<Parser> = RefCell::new(Parser::new());
}
pub fn parse(src: &Rope, old_tree: Option<&Tree>) -> Tree {
let t = Instant::now();
let tree = PARSER_UVL
.with(|parser| {
if parser.borrow().language().is_none() {
let _ = parser.borrow_mut().set_language(TS.uvl);
}
parser.borrow_mut().parse_with(
&mut |byte_offset: usize, _: Point| {
if byte_offset > src.len_bytes() {
""
} else {
src.byte_slice(byte_offset..).chunks().next().unwrap_or("")
}
},
old_tree,
)
})
.unwrap();
info!("Parsed in {:?}", t.elapsed());
tree
}
pub fn parse_json(src: &Rope, old_tree: Option<&Tree>) -> Tree {
let t = Instant::now();
let tree = PARSER_JSON
.with(|parser| {
if parser.borrow().language().is_none() {
let _ = parser.borrow_mut().set_language(TS.json);
}
parser.borrow_mut().parse_with(
&mut |byte_offset: usize, _: Point| {
if byte_offset > src.len_bytes() {
""
} else {
src.byte_slice(byte_offset..).chunks().next().unwrap_or("")
}
},
old_tree,
)
})
.unwrap();
info!("Parsed in {:?}", t.elapsed());
tree
}
pub trait SymbolSlice {
fn slice(&self, node: Node) -> Cow<str> {
self.slice_raw(node.byte_range())
}
fn name(&self, node: Node) -> Ustr {
Ustr::from(&self.slice_raw(node.byte_range()))
}
fn slice_raw(&self, node: Span) -> Cow<'_, str>;
}
impl SymbolSlice for str {
fn slice_raw(&self, node: Span) -> Cow<str> {
Cow::Borrowed(&self[node])
}
}
impl SymbolSlice for String {
fn slice_raw(&self, node: Span) -> Cow<str> {
Cow::Borrowed(&self[node])
}
}
impl SymbolSlice for Rope {
fn slice_raw(&self, node: Span) -> Cow<str> {
self.byte_slice(node).into()
}
}
pub fn parse_name<S: SymbolSlice>(node: Node, source: &S) -> Option<SymbolSpan> {
if node.is_missing() {
Some(SymbolSpan {
name: Ustr::from("__MISSING_NAME__"),
span: node.byte_range(),
})
} else {
match node.kind() {
"name" => Some(SymbolSpan {
name: source.name(node),
span: node.byte_range(),
}),
_ => None,
}
}
}
pub fn parse_path<S: SymbolSlice>(node: Node, source: &S) -> Option<Path> {
if let Some(name) = parse_name(node, source) {
Some(Path {
names: vec![name.name],
spans: vec![name.span],
})
} else if node.kind() == "path" {
let mut cursor = node.walk();
cursor.goto_first_child();
let mut path = Path::default();
loop {
if let Some(name) = parse_name(cursor.node(), source) {
path.names.push(name.name);
path.spans.push(name.span);
}
if !cursor.goto_next_sibling() {
break;
}
}
Some(path)
} else {
None
}
}
pub fn parse_lang_lvl<S: SymbolSlice>(node: Node, source: &S) -> Option<SymbolSpan> {
if node.is_missing() {
Some(SymbolSpan {
name: Ustr::from("__MISSING_NAME__"),
span: node.byte_range(),
})
} else {
match node.kind() {
"major_lvl" | "minor_lvl" | "name" => Some(SymbolSpan {
name: source.name(node),
span: node.byte_range(),
}),
_ => None,
}
}
}
pub fn parse_lang_lvl_path<S: SymbolSlice>(node: Node, source: &S) -> Option<Path> {
if let Some(name) = parse_lang_lvl(node, source) {
Some(Path {
names: vec![name.name],
spans: vec![name.span],
})
} else if node.kind() == "lang_lvl" {
let mut cursor = node.walk();
cursor.goto_first_child();
let mut path = Path::default();
loop {
if let Some(name) = parse_lang_lvl(cursor.node(), source) {
path.names.push(name.name);
path.spans.push(name.span);
}
if !cursor.goto_next_sibling() {
break;
}
}
Some(path)
} else {
None
}
}
pub fn parse_or_lang_lvl<S: SymbolSlice>(node: Node, source: &S) -> Option<Path> {
parse_path(node, source).or_else(|| parse_lang_lvl_path(node, source))
}
pub fn move_span(span: Span, offset: usize) -> Span {
span.start + offset..span.end + offset
}