Named captures are dynamic
New c api for getting list of syntax_type names.
This commit is contained in:
parent
3bcb1f8c94
commit
54586c4e5b
3 changed files with 69 additions and 98 deletions
|
|
@ -18,17 +18,6 @@ typedef enum {
|
|||
TSTagsInvalidQuery,
|
||||
} TSTagsError;
|
||||
|
||||
typedef enum {
|
||||
TSSyntaxTypeFunction,
|
||||
TSSyntaxTypeMethod,
|
||||
TSSyntaxTypeClass,
|
||||
TSSyntaxTypeModule,
|
||||
TSSyntaxTypeCall,
|
||||
TSSyntaxTypeType,
|
||||
TSSyntaxTypeInterface,
|
||||
TSSyntaxTypeImplementation,
|
||||
} TSTagSyntaxType;
|
||||
|
||||
typedef struct {
|
||||
uint32_t start_byte;
|
||||
uint32_t end_byte;
|
||||
|
|
@ -40,7 +29,7 @@ typedef struct {
|
|||
TSPoint end_point;
|
||||
uint32_t docs_start_byte;
|
||||
uint32_t docs_end_byte;
|
||||
TSTagSyntaxType syntax_type;
|
||||
uint32_t syntax_type_id;
|
||||
bool is_definition;
|
||||
} TSTag;
|
||||
|
||||
|
|
@ -93,6 +82,9 @@ uint32_t ts_tags_buffer_tags_len(const TSTagsBuffer *);
|
|||
const char *ts_tags_buffer_docs(const TSTagsBuffer *);
|
||||
uint32_t ts_tags_buffer_docs_len(const TSTagsBuffer *);
|
||||
|
||||
// Get the syntax kinds for a scope.
|
||||
const char **ts_tagger_syntax_kinds_for_scope_name(const TSTagger *, const char *scope_name, uint32_t *len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use super::{Error, SyntaxType, TagsConfiguration, TagsContext};
|
||||
use super::{Error, TagsConfiguration, TagsContext};
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CStr;
|
||||
use std::process::abort;
|
||||
|
|
@ -19,19 +19,6 @@ pub enum TSTagsError {
|
|||
Unknown,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum TSSyntaxType {
|
||||
Function,
|
||||
Method,
|
||||
Class,
|
||||
Module,
|
||||
Call,
|
||||
Type,
|
||||
Interface,
|
||||
Implementation,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct TSPoint {
|
||||
row: u32,
|
||||
|
|
@ -50,7 +37,7 @@ pub struct TSTag {
|
|||
pub end_point: TSPoint,
|
||||
pub docs_start_byte: u32,
|
||||
pub docs_end_byte: u32,
|
||||
pub syntax_type: TSSyntaxType,
|
||||
pub syntax_type_id: u32,
|
||||
pub is_definition: bool,
|
||||
}
|
||||
|
||||
|
|
@ -173,16 +160,7 @@ pub extern "C" fn ts_tagger_tag(
|
|||
},
|
||||
docs_start_byte: prev_docs_len as u32,
|
||||
docs_end_byte: buffer.docs.len() as u32,
|
||||
syntax_type: match tag.syntax_type {
|
||||
SyntaxType::Function => TSSyntaxType::Function,
|
||||
SyntaxType::Method => TSSyntaxType::Method,
|
||||
SyntaxType::Class => TSSyntaxType::Class,
|
||||
SyntaxType::Module => TSSyntaxType::Module,
|
||||
SyntaxType::Call => TSSyntaxType::Call,
|
||||
SyntaxType::Type => TSSyntaxType::Type,
|
||||
SyntaxType::Interface => TSSyntaxType::Interface,
|
||||
SyntaxType::Implementation => TSSyntaxType::Implementation,
|
||||
},
|
||||
syntax_type_id: tag.syntax_type_id,
|
||||
is_definition: tag.is_definition,
|
||||
});
|
||||
}
|
||||
|
|
@ -231,6 +209,24 @@ pub extern "C" fn ts_tags_buffer_docs_len(this: *const TSTagsBuffer) -> u32 {
|
|||
buffer.docs.len() as u32
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ts_tagger_syntax_kinds_for_scope_name(
|
||||
this: *mut TSTagger,
|
||||
scope_name: *const i8,
|
||||
len: *mut u32,
|
||||
) -> *const *const i8 {
|
||||
let tagger = unwrap_mut_ptr(this);
|
||||
let scope_name = unsafe { unwrap(CStr::from_ptr(scope_name).to_str()) };
|
||||
let len = unwrap_mut_ptr(len);
|
||||
|
||||
*len = 0;
|
||||
if let Some(config) = tagger.languages.get(scope_name) {
|
||||
*len = config.c_syntax_type_names.len() as u32;
|
||||
return config.c_syntax_type_names.as_ptr() as *const *const i8
|
||||
}
|
||||
std::ptr::null()
|
||||
}
|
||||
|
||||
fn unwrap_ptr<'a, T>(result: *const T) -> &'a T {
|
||||
unsafe { result.as_ref() }.unwrap_or_else(|| {
|
||||
eprintln!("{}:{} - pointer must not be null", file!(), line!());
|
||||
|
|
|
|||
105
tags/src/lib.rs
105
tags/src/lib.rs
|
|
@ -5,6 +5,7 @@ use regex::Regex;
|
|||
use std::ops::Range;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::{fmt, mem, str};
|
||||
use std::ffi::CStr;
|
||||
use std::collections::HashMap;
|
||||
use tree_sitter::{
|
||||
Language, Parser, Point, Query, QueryCursor, QueryError, QueryPredicateArg, Tree,
|
||||
|
|
@ -19,6 +20,8 @@ const CANCELLATION_CHECK_INTERVAL: usize = 100;
|
|||
pub struct TagsConfiguration {
|
||||
pub language: Language,
|
||||
pub query: Query,
|
||||
syntax_type_names: Vec<Box<[u8]>>,
|
||||
c_syntax_type_names: Vec<*const u8>,
|
||||
capture_map: HashMap<u32, NamedCapture>,
|
||||
doc_capture_index: Option<u32>,
|
||||
name_capture_index: Option<u32>,
|
||||
|
|
@ -30,24 +33,10 @@ pub struct TagsConfiguration {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct NamedCapture {
|
||||
pub syntax_type: SyntaxType,
|
||||
pub syntax_type_id: u32,
|
||||
pub is_definition: bool,
|
||||
}
|
||||
|
||||
// Should stay in sync with list of valid syntax types in semantic.
|
||||
// See: https://github.com/github/semantic/blob/621696f5bc523a651f1cf9fc2ac58c557ea02d07/proto/semantic.proto#L165-L174
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum SyntaxType {
|
||||
Function,
|
||||
Method,
|
||||
Class,
|
||||
Module,
|
||||
Call,
|
||||
Type,
|
||||
Interface,
|
||||
Implementation,
|
||||
}
|
||||
|
||||
pub struct TagsContext {
|
||||
parser: Parser,
|
||||
cursor: QueryCursor,
|
||||
|
|
@ -61,7 +50,7 @@ pub struct Tag {
|
|||
pub span: Range<Point>,
|
||||
pub docs: Option<String>,
|
||||
pub is_definition: bool,
|
||||
pub syntax_type: SyntaxType,
|
||||
pub syntax_type_id: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
|
@ -70,6 +59,7 @@ pub enum Error {
|
|||
Regex(regex::Error),
|
||||
Cancelled,
|
||||
InvalidLanguage,
|
||||
InvalidCapture(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
|
@ -120,11 +110,13 @@ impl TagsConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
let mut capture_map: HashMap<u32, NamedCapture> = HashMap::new();
|
||||
let mut capture_map = HashMap::new();
|
||||
let mut syntax_type_names = Vec::new();
|
||||
let mut doc_capture_index = None;
|
||||
let mut name_capture_index = None;
|
||||
let mut local_scope_capture_index = None;
|
||||
let mut local_definition_capture_index = None;
|
||||
let mut syntax_type_id = 0;
|
||||
for (i, name) in query.capture_names().iter().enumerate() {
|
||||
match name.as_str() {
|
||||
"" => continue,
|
||||
|
|
@ -132,12 +124,32 @@ impl TagsConfiguration {
|
|||
"doc" => doc_capture_index = Some(i as u32),
|
||||
"local.scope" => local_scope_capture_index = Some(i as u32),
|
||||
"local.definition" => local_definition_capture_index = Some(i as u32),
|
||||
_ => if let Some(nc) = NamedCapture::new(name) {
|
||||
capture_map.insert(i as u32, nc);
|
||||
"local.reference" => continue,
|
||||
_ => {
|
||||
let mut is_definition = false;
|
||||
|
||||
let kind = if name.starts_with("definition.") {
|
||||
is_definition = true;
|
||||
name.trim_start_matches("definition.")
|
||||
} else if name.starts_with("reference.") {
|
||||
name.trim_start_matches("reference.")
|
||||
} else {
|
||||
return Err(Error::InvalidCapture(name.to_string()))
|
||||
}.to_string()+"\0";
|
||||
|
||||
capture_map.insert(i as u32, NamedCapture{ syntax_type_id, is_definition });
|
||||
syntax_type_id+=1;
|
||||
if let Ok(cstr) = CStr::from_bytes_with_nul(kind.as_bytes()) {
|
||||
syntax_type_names.push(cstr.to_bytes_with_nul().to_vec().into_boxed_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let c_syntax_type_names = syntax_type_names.iter().map( |s| {
|
||||
s.as_ptr()
|
||||
}).collect();
|
||||
|
||||
let pattern_info = (0..query.pattern_count())
|
||||
.map(|pattern_index| {
|
||||
let mut info = PatternInfo::default();
|
||||
|
|
@ -182,6 +194,8 @@ impl TagsConfiguration {
|
|||
Ok(TagsConfiguration {
|
||||
language,
|
||||
query,
|
||||
syntax_type_names,
|
||||
c_syntax_type_names,
|
||||
capture_map,
|
||||
doc_capture_index,
|
||||
name_capture_index,
|
||||
|
|
@ -191,6 +205,13 @@ impl TagsConfiguration {
|
|||
pattern_info,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn syntax_type_name(&self, id: u32) -> &str {
|
||||
unsafe {
|
||||
let cstr = CStr::from_ptr(self.syntax_type_names[id as usize].as_ptr() as *const i8).to_bytes();
|
||||
str::from_utf8(cstr).expect("syntax type name was not valid utf-8")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TagsContext {
|
||||
|
|
@ -301,7 +322,7 @@ where
|
|||
let mut name_range = None;
|
||||
let mut doc_nodes = Vec::new();
|
||||
let mut tag_node = None;
|
||||
let mut syntax_type = SyntaxType::Function;
|
||||
let mut syntax_type_id = 0;
|
||||
let mut is_definition = false;
|
||||
let mut docs_adjacent_node = None;
|
||||
|
||||
|
|
@ -320,7 +341,7 @@ where
|
|||
|
||||
if let Some(named_capture) = self.config.capture_map.get(&capture.index) {
|
||||
tag_node = Some(capture.node);
|
||||
syntax_type = named_capture.syntax_type;
|
||||
syntax_type_id = named_capture.syntax_type_id;
|
||||
is_definition = named_capture.is_definition;
|
||||
}
|
||||
}
|
||||
|
|
@ -407,7 +428,7 @@ where
|
|||
range,
|
||||
name_range,
|
||||
docs,
|
||||
syntax_type,
|
||||
syntax_type_id,
|
||||
is_definition,
|
||||
};
|
||||
}
|
||||
|
|
@ -421,7 +442,7 @@ where
|
|||
range,
|
||||
name_range,
|
||||
docs,
|
||||
syntax_type,
|
||||
syntax_type_id,
|
||||
is_definition,
|
||||
},
|
||||
mat.pattern_index,
|
||||
|
|
@ -440,44 +461,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl NamedCapture {
|
||||
pub fn new(name: &String) -> Option<NamedCapture> {
|
||||
let mut is_definition = false;
|
||||
|
||||
let kind = if name.starts_with("definition.") {
|
||||
is_definition = true;
|
||||
name.trim_start_matches("definition.")
|
||||
} else if name.starts_with("reference.") {
|
||||
name.trim_start_matches("reference.")
|
||||
} else {
|
||||
name
|
||||
};
|
||||
|
||||
let syntax_type = match kind.as_ref() {
|
||||
"function" => {is_definition = true; SyntaxType::Function},
|
||||
"method" => {is_definition = true; SyntaxType::Method},
|
||||
"class" => {is_definition = true; SyntaxType::Class},
|
||||
"module" => {is_definition = true; SyntaxType::Module},
|
||||
"call" => SyntaxType::Call,
|
||||
"type" => SyntaxType::Type,
|
||||
"interface" => SyntaxType::Interface,
|
||||
"implementation" => SyntaxType::Implementation,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
return Some(NamedCapture{
|
||||
syntax_type,
|
||||
is_definition
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SyntaxType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
format!("{:?}", self).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<regex::Error> for Error {
|
||||
fn from(error: regex::Error) -> Self {
|
||||
Error::Regex(error)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue