tags: Add @ignore capture
This commit is contained in:
parent
4ec7d80968
commit
e89a19a158
2 changed files with 153 additions and 109 deletions
|
|
@ -68,11 +68,13 @@ const JS_TAG_QUERY: &'static str = r#"
|
|||
|
||||
const RUBY_TAG_QUERY: &'static str = r#"
|
||||
(method
|
||||
name: (identifier) @name) @definition.method
|
||||
name: (_) @name) @definition.method
|
||||
|
||||
(method_call
|
||||
method: (identifier) @name) @reference.call
|
||||
|
||||
(setter (identifier) @ignore)
|
||||
|
||||
((identifier) @name @reference.call
|
||||
(#is-not? local))
|
||||
"#;
|
||||
|
|
@ -207,7 +209,7 @@ fn test_tags_ruby() {
|
|||
"
|
||||
b = 1
|
||||
|
||||
def foo()
|
||||
def foo=()
|
||||
c = 1
|
||||
|
||||
# a is a method because it is not in scope
|
||||
|
|
@ -239,7 +241,7 @@ fn test_tags_ruby() {
|
|||
))
|
||||
.collect::<Vec<_>>(),
|
||||
&[
|
||||
("foo", "method", (2, 4)),
|
||||
("foo=", "method", (2, 4)),
|
||||
("bar", "call", (7, 4)),
|
||||
("a", "call", (7, 8)),
|
||||
("b", "call", (7, 11)),
|
||||
|
|
|
|||
254
tags/src/lib.rs
254
tags/src/lib.rs
|
|
@ -25,6 +25,7 @@ pub struct TagsConfiguration {
|
|||
capture_map: HashMap<u32, NamedCapture>,
|
||||
doc_capture_index: Option<u32>,
|
||||
name_capture_index: Option<u32>,
|
||||
ignore_capture_index: Option<u32>,
|
||||
local_scope_capture_index: Option<u32>,
|
||||
local_definition_capture_index: Option<u32>,
|
||||
tags_pattern_index: usize,
|
||||
|
|
@ -128,12 +129,14 @@ impl TagsConfiguration {
|
|||
let mut syntax_type_names = Vec::new();
|
||||
let mut doc_capture_index = None;
|
||||
let mut name_capture_index = None;
|
||||
let mut ignore_capture_index = None;
|
||||
let mut local_scope_capture_index = None;
|
||||
let mut local_definition_capture_index = None;
|
||||
for (i, name) in query.capture_names().iter().enumerate() {
|
||||
match name.as_str() {
|
||||
"" => continue,
|
||||
"name" => name_capture_index = Some(i as u32),
|
||||
"ignore" => ignore_capture_index = Some(i as u32),
|
||||
"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),
|
||||
|
|
@ -222,6 +225,7 @@ impl TagsConfiguration {
|
|||
capture_map,
|
||||
doc_capture_index,
|
||||
name_capture_index,
|
||||
ignore_capture_index,
|
||||
tags_pattern_index,
|
||||
local_scope_capture_index,
|
||||
local_definition_capture_index,
|
||||
|
|
@ -311,7 +315,12 @@ where
|
|||
if self.tag_queue.len() > 1
|
||||
&& self.tag_queue[0].0.name_range.end < last_entry.0.name_range.start
|
||||
{
|
||||
return Some(Ok(self.tag_queue.remove(0).0));
|
||||
let tag = self.tag_queue.remove(0).0;
|
||||
if tag.is_ignored() {
|
||||
continue;
|
||||
} else {
|
||||
return Some(Ok(tag));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -350,10 +359,16 @@ where
|
|||
let mut syntax_type_id = 0;
|
||||
let mut is_definition = false;
|
||||
let mut docs_adjacent_node = None;
|
||||
let mut is_ignored = false;
|
||||
|
||||
for capture in mat.captures {
|
||||
let index = Some(capture.index);
|
||||
|
||||
if index == self.config.ignore_capture_index {
|
||||
is_ignored = true;
|
||||
name_node = Some(capture.node);
|
||||
}
|
||||
|
||||
if index == self.config.pattern_info[mat.pattern_index].docs_adjacent_capture {
|
||||
docs_adjacent_node = Some(capture.node);
|
||||
}
|
||||
|
|
@ -371,129 +386,137 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
if let (Some(tag_node), Some(name_node)) = (tag_node, name_node) {
|
||||
if name_node.has_error() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(name_node) = name_node {
|
||||
let name_range = name_node.byte_range();
|
||||
|
||||
if pattern_info.name_must_be_non_local {
|
||||
let mut is_local = false;
|
||||
for scope in self.scopes.iter().rev() {
|
||||
if scope.range.start <= name_range.start
|
||||
&& scope.range.end >= name_range.end
|
||||
{
|
||||
if scope
|
||||
.local_defs
|
||||
.iter()
|
||||
.any(|d| d.name == &self.source[name_range.clone()])
|
||||
{
|
||||
is_local = true;
|
||||
break;
|
||||
}
|
||||
if !scope.inherits {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if is_local {
|
||||
let tag;
|
||||
if let Some(tag_node) = tag_node {
|
||||
if name_node.has_error() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If needed, filter the doc nodes based on their ranges, selecting
|
||||
// only the slice that are adjacent to some specified node.
|
||||
let mut docs_start_index = 0;
|
||||
if let (Some(docs_adjacent_node), false) =
|
||||
(docs_adjacent_node, doc_nodes.is_empty())
|
||||
{
|
||||
docs_start_index = doc_nodes.len();
|
||||
let mut start_row = docs_adjacent_node.start_position().row;
|
||||
while docs_start_index > 0 {
|
||||
let doc_node = &doc_nodes[docs_start_index - 1];
|
||||
let prev_doc_end_row = doc_node.end_position().row;
|
||||
if prev_doc_end_row + 1 >= start_row {
|
||||
docs_start_index -= 1;
|
||||
start_row = doc_node.start_position().row;
|
||||
} else {
|
||||
break;
|
||||
if pattern_info.name_must_be_non_local {
|
||||
let mut is_local = false;
|
||||
for scope in self.scopes.iter().rev() {
|
||||
if scope.range.start <= name_range.start
|
||||
&& scope.range.end >= name_range.end
|
||||
{
|
||||
if scope
|
||||
.local_defs
|
||||
.iter()
|
||||
.any(|d| d.name == &self.source[name_range.clone()])
|
||||
{
|
||||
is_local = true;
|
||||
break;
|
||||
}
|
||||
if !scope.inherits {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if is_local {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a doc string from all of the doc nodes, applying any strip regexes.
|
||||
let mut docs = None;
|
||||
for doc_node in &doc_nodes[docs_start_index..] {
|
||||
if let Ok(content) = str::from_utf8(&self.source[doc_node.byte_range()]) {
|
||||
let content = if let Some(regex) = &pattern_info.doc_strip_regex {
|
||||
regex.replace_all(content, "").to_string()
|
||||
} else {
|
||||
content.to_string()
|
||||
};
|
||||
match &mut docs {
|
||||
None => docs = Some(content),
|
||||
Some(d) => {
|
||||
d.push('\n');
|
||||
d.push_str(&content);
|
||||
// If needed, filter the doc nodes based on their ranges, selecting
|
||||
// only the slice that are adjacent to some specified node.
|
||||
let mut docs_start_index = 0;
|
||||
if let (Some(docs_adjacent_node), false) =
|
||||
(docs_adjacent_node, doc_nodes.is_empty())
|
||||
{
|
||||
docs_start_index = doc_nodes.len();
|
||||
let mut start_row = docs_adjacent_node.start_position().row;
|
||||
while docs_start_index > 0 {
|
||||
let doc_node = &doc_nodes[docs_start_index - 1];
|
||||
let prev_doc_end_row = doc_node.end_position().row;
|
||||
if prev_doc_end_row + 1 >= start_row {
|
||||
docs_start_index -= 1;
|
||||
start_row = doc_node.start_position().row;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let range = tag_node.byte_range();
|
||||
let span = name_node.start_position()..name_node.end_position();
|
||||
// Generate a doc string from all of the doc nodes, applying any strip regexes.
|
||||
let mut docs = None;
|
||||
for doc_node in &doc_nodes[docs_start_index..] {
|
||||
if let Ok(content) = str::from_utf8(&self.source[doc_node.byte_range()])
|
||||
{
|
||||
let content = if let Some(regex) = &pattern_info.doc_strip_regex {
|
||||
regex.replace_all(content, "").to_string()
|
||||
} else {
|
||||
content.to_string()
|
||||
};
|
||||
match &mut docs {
|
||||
None => docs = Some(content),
|
||||
Some(d) => {
|
||||
d.push('\n');
|
||||
d.push_str(&content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute tag properties that depend on the text of the containing line. If the
|
||||
// previous tag occurred on the same line, then reuse results from the previous tag.
|
||||
let line_range;
|
||||
let mut prev_utf16_column = 0;
|
||||
let mut prev_utf8_byte = name_range.start - span.start.column;
|
||||
let line_info = self.prev_line_info.as_ref().and_then(|info| {
|
||||
if info.utf8_position.row == span.start.row {
|
||||
Some(info)
|
||||
let range = tag_node.byte_range();
|
||||
let span = name_node.start_position()..name_node.end_position();
|
||||
|
||||
// Compute tag properties that depend on the text of the containing line. If the
|
||||
// previous tag occurred on the same line, then reuse results from the previous tag.
|
||||
let line_range;
|
||||
let mut prev_utf16_column = 0;
|
||||
let mut prev_utf8_byte = name_range.start - span.start.column;
|
||||
let line_info = self.prev_line_info.as_ref().and_then(|info| {
|
||||
if info.utf8_position.row == span.start.row {
|
||||
Some(info)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
if let Some(line_info) = line_info {
|
||||
line_range = line_info.line_range.clone();
|
||||
if line_info.utf8_position.column <= span.start.column {
|
||||
prev_utf8_byte = line_info.utf8_byte;
|
||||
prev_utf16_column = line_info.utf16_column;
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
if let Some(line_info) = line_info {
|
||||
line_range = line_info.line_range.clone();
|
||||
if line_info.utf8_position.column <= span.start.column {
|
||||
prev_utf8_byte = line_info.utf8_byte;
|
||||
prev_utf16_column = line_info.utf16_column;
|
||||
line_range = self::line_range(
|
||||
self.source,
|
||||
name_range.start,
|
||||
span.start,
|
||||
MAX_LINE_LEN,
|
||||
);
|
||||
}
|
||||
|
||||
let utf16_start_column = prev_utf16_column
|
||||
+ utf16_len(&self.source[prev_utf8_byte..name_range.start]);
|
||||
let utf16_end_column =
|
||||
utf16_start_column + utf16_len(&self.source[name_range.clone()]);
|
||||
let utf16_column_range = utf16_start_column..utf16_end_column;
|
||||
|
||||
self.prev_line_info = Some(LineInfo {
|
||||
utf8_position: span.end,
|
||||
utf8_byte: name_range.end,
|
||||
utf16_column: utf16_end_column,
|
||||
line_range: line_range.clone(),
|
||||
});
|
||||
tag = Tag {
|
||||
line_range,
|
||||
span,
|
||||
utf16_column_range,
|
||||
range,
|
||||
name_range,
|
||||
docs,
|
||||
is_definition,
|
||||
syntax_type_id,
|
||||
};
|
||||
} else if is_ignored {
|
||||
tag = Tag::ignored(name_range);
|
||||
} else {
|
||||
line_range = self::line_range(
|
||||
self.source,
|
||||
name_range.start,
|
||||
span.start,
|
||||
MAX_LINE_LEN,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
let utf16_start_column = prev_utf16_column
|
||||
+ utf16_len(&self.source[prev_utf8_byte..name_range.start]);
|
||||
let utf16_end_column =
|
||||
utf16_start_column + utf16_len(&self.source[name_range.clone()]);
|
||||
let utf16_column_range = utf16_start_column..utf16_end_column;
|
||||
|
||||
self.prev_line_info = Some(LineInfo {
|
||||
utf8_position: span.end,
|
||||
utf8_byte: name_range.end,
|
||||
utf16_column: utf16_end_column,
|
||||
line_range: line_range.clone(),
|
||||
});
|
||||
let tag = Tag {
|
||||
line_range,
|
||||
span,
|
||||
utf16_column_range,
|
||||
range,
|
||||
name_range,
|
||||
docs,
|
||||
is_definition,
|
||||
syntax_type_id,
|
||||
};
|
||||
|
||||
// Only create one tag per node. The tag queue is sorted by node position
|
||||
// to allow for fast lookup.
|
||||
match self.tag_queue.binary_search_by_key(
|
||||
|
|
@ -521,6 +544,25 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl Tag {
|
||||
fn ignored(name_range: Range<usize>) -> Self {
|
||||
Tag {
|
||||
name_range,
|
||||
line_range: 0..0,
|
||||
span: Point::new(0, 0)..Point::new(0, 0),
|
||||
utf16_column_range: 0..0,
|
||||
range: usize::MAX..usize::MAX,
|
||||
docs: None,
|
||||
is_definition: false,
|
||||
syntax_type_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_ignored(&self) -> bool {
|
||||
self.range.start == usize::MAX
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue