Skip to content

Commit

Permalink
feat: support !reference for rules
Browse files Browse the repository at this point in the history
Support !reference. Currently only for rules.
Supports:
- definition
- autocomplete
- hover
  • Loading branch information
alesbrelih committed Apr 28, 2024
1 parent 0e60c9d commit 70b8760
Show file tree
Hide file tree
Showing 6 changed files with 255 additions and 16 deletions.
114 changes: 109 additions & 5 deletions src/gitlab_ci_ls_parser/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use lsp_types::{
use super::{
fs_utils, parser, parser_utils, treesitter, CompletionResult, DefinitionResult,
DiagnosticsResult, GitlabElement, HoverResult, IncludeInformation, LSPCompletion, LSPConfig,
LSPLocation, LSPPosition, LSPResult, Range, ReferencesResult,
LSPLocation, LSPPosition, LSPResult, Range, ReferencesResult, RuleReference,
};

#[allow(clippy::module_name_repetitions)]
Expand Down Expand Up @@ -100,6 +100,33 @@ impl LSPHandlers {

None
}
parser::PositionType::RuleReference(RuleReference { node }) => {
for (document_uri, n) in nodes.iter() {
for (key, content) in n {
if key.eq(&node) {
let cnt = match self.parser.get_full_definition(
GitlabElement {
key: key.clone(),
content: Some(content.to_string()),
uri: document_uri.to_string(),
..Default::default()
},
&store,
) {
Ok(c) => c,
Err(err) => return Some(LSPResult::Error(err)),
};

return Some(LSPResult::Hover(HoverResult {
id: request.id,
content: format!("```yaml\n{cnt}\n```"),
}));
}
}
}

None
}
_ => None,
}
}
Expand Down Expand Up @@ -201,6 +228,7 @@ impl LSPHandlers {
None
}

#[allow(clippy::too_many_lines)]
pub fn on_definition(&self, request: Request) -> Option<LSPResult> {
let params = serde_json::from_value::<GotoTypeDefinitionParams>(request.params).ok()?;

Expand Down Expand Up @@ -298,6 +326,16 @@ impl LSPHandlers {

locations.append(&mut root);
}
parser::PositionType::RuleReference(RuleReference { node }) => {
for (uri, content) in store {
if let Some(element) = self.parser.get_root_node(uri, content, &node) {
locations.push(LSPLocation {
uri: uri.clone(),
range: element.range,
});
}
}
}
parser::PositionType::None => {
error!("invalid position type for goto def");
return None;
Expand Down Expand Up @@ -443,6 +481,9 @@ impl LSPHandlers {
parser::PositionType::Extend => self.on_completion_extends(line, position).ok()?,
parser::PositionType::Variable => self.on_completion_variables(line, position).ok()?,
parser::PositionType::Needs(_) => self.on_completion_needs(line, position).ok()?,
parser::PositionType::RuleReference(_) => {
self.on_completion_rule_reference(line, position).ok()?
}
_ => return None,
};

Expand All @@ -469,7 +510,10 @@ impl LSPHandlers {
position.character as usize,
|c: char| c.is_whitespace(),
);
let after = parser_utils::ParserUtils::word_after_cursor(line, position.character as usize);
let after =
parser_utils::ParserUtils::word_after_cursor(line, position.character as usize, |c| {
c.is_whitespace()
});

let items = stages
.keys()
Expand Down Expand Up @@ -513,7 +557,10 @@ impl LSPHandlers {
|c: char| c.is_whitespace(),
);

let after = parser_utils::ParserUtils::word_after_cursor(line, position.character as usize);
let after =
parser_utils::ParserUtils::word_after_cursor(line, position.character as usize, |c| {
c.is_whitespace()
});

let items = nodes
.values()
Expand Down Expand Up @@ -563,7 +610,10 @@ impl LSPHandlers {
|c: char| c == '$',
);

let after = parser_utils::ParserUtils::word_after_cursor(line, position.character as usize);
let after =
parser_utils::ParserUtils::word_after_cursor(line, position.character as usize, |c| {
c.is_whitespace()
});

let items = variables
.keys()
Expand Down Expand Up @@ -592,6 +642,57 @@ impl LSPHandlers {
Ok(items)
}

fn on_completion_rule_reference(
&self,
line: &str,
position: Position,
) -> anyhow::Result<Vec<LSPCompletion>> {
let nodes = self
.nodes
.lock()
.map_err(|err| anyhow!("failed to lock nodes: {}", err))?;

let word = parser_utils::ParserUtils::word_before_cursor(
line,
position.character as usize,
|c: char| c == '\'' || c == '"',
);

let after =
parser_utils::ParserUtils::word_after_cursor(line, position.character as usize, |c| {
c == '\'' || c == '"'
});

let items = nodes
.values()
.flat_map(|needs| needs.iter())
.filter(|(node_key, _)| node_key.contains(word))
.flat_map(
|(node_key, node_description)| -> anyhow::Result<LSPCompletion> {
Ok(LSPCompletion {
label: node_key.clone(),
details: Some(node_description.clone()),
location: LSPLocation {
range: Range {
start: LSPPosition {
line: position.line,
character: position.character - u32::try_from(word.len())?,
},
end: LSPPosition {
line: position.line,
character: position.character + u32::try_from(after.len())?,
},
},
..Default::default()
},
})
},
)
.collect();

Ok(items)
}

fn on_completion_needs(
&self,
line: &str,
Expand All @@ -606,7 +707,10 @@ impl LSPHandlers {
position.character as usize,
|c: char| c.is_whitespace(),
);
let after = parser_utils::ParserUtils::word_after_cursor(line, position.character as usize);
let after =
parser_utils::ParserUtils::word_after_cursor(line, position.character as usize, |c| {
c.is_whitespace()
});

let items = nodes
.values()
Expand Down
5 changes: 5 additions & 0 deletions src/gitlab_ci_ls_parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ pub struct IncludeInformation {
pub basic: Option<Include>,
}

#[derive(Debug, Default)]
pub struct RuleReference {
pub node: String,
}

#[derive(Debug)]
pub struct NodeDefinition {
pub name: String,
Expand Down
3 changes: 2 additions & 1 deletion src/gitlab_ci_ls_parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};

use super::{
fs_utils, git, treesitter, GitlabElement, GitlabFile, IncludeInformation, NodeDefinition,
ParseResults,
ParseResults, RuleReference,
};

#[derive(Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -99,6 +99,7 @@ pub enum PositionType {
RootNode,
Include(IncludeInformation),
Needs(NodeDefinition),
RuleReference(RuleReference),
}

impl ParserImpl {
Expand Down
8 changes: 6 additions & 2 deletions src/gitlab_ci_ls_parser/parser_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ impl ParserUtils {
&line[start..char_index]
}

pub fn word_after_cursor(line: &str, char_index: usize) -> &str {
pub fn word_after_cursor(
line: &str,
char_index: usize,
predicate: fn(c: char) -> bool,
) -> &str {
if char_index >= line.len() {
return "";
}
Expand All @@ -50,7 +54,7 @@ impl ParserUtils {

let end = line[start..]
.char_indices()
.find(|&(_, c)| c.is_whitespace())
.find(|&(_, c)| predicate(c))
.map_or(line.len(), |(idx, _)| start + idx);

&line[start..end]
Expand Down
Loading

0 comments on commit 70b8760

Please sign in to comment.