Skip to content

Commit

Permalink
feat: support basic include format
Browse files Browse the repository at this point in the history
If its basic format without local/remote it should automatically know if
its remote or local.
  • Loading branch information
alesbrelih committed Apr 8, 2024
1 parent 52c90a6 commit 3f22d24
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 74 deletions.
106 changes: 68 additions & 38 deletions src/gitlab_ci_ls_parser/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,31 +318,17 @@ impl LSPHandlers {
local: Some(local),
remote: None,
remote_url: None,
basic: None,
} => {
let local =
parser_utils::ParserUtils::strip_quotes(&local.path).trim_start_matches('.');
let local = parser_utils::ParserUtils::strip_quotes(&local.path);

store
.keys()
.find(|uri| uri.ends_with(local))
.map(|uri| LSPLocation {
uri: uri.clone(),
range: Range {
start: LSPPosition {
line: 0,
character: 0,
},
end: LSPPosition {
line: 0,
character: 0,
},
},
})
LSPHandlers::on_definition_local(local, store)
}
IncludeInformation {
local: None,
remote: Some(remote),
remote_url: None,
basic: None,
} => {
let file = remote.file?;
let file = parser_utils::ParserUtils::strip_quotes(&file).trim_start_matches('/');
Expand Down Expand Up @@ -370,32 +356,76 @@ impl LSPHandlers {
local: None,
remote: None,
remote_url: Some(remote_url),
basic: None,
} => {
let path_hash = parser_utils::ParserUtils::remote_path_to_hash(
parser_utils::ParserUtils::strip_quotes(remote_url.path.as_str()),
);

store
.keys()
.find(|uri| uri.ends_with(format!("_{path_hash}.yaml").as_str()))
.map(|uri| LSPLocation {
uri: uri.clone(),
range: Range {
start: LSPPosition {
line: 0,
character: 0,
},
end: LSPPosition {
line: 0,
character: 0,
},
},
})
let remote_url = parser_utils::ParserUtils::strip_quotes(remote_url.path.as_str());
LSPHandlers::on_definition_remote(remote_url, store)
}
IncludeInformation {
local: None,
remote: None,
remote_url: None,
basic: Some(basic_url),
} => {
let url = parser_utils::ParserUtils::strip_quotes(&basic_url.path);
if let Ok(url) = Url::parse(url) {
LSPHandlers::on_definition_remote(url.as_str(), store)
} else {
LSPHandlers::on_definition_local(url, store)
}
}
_ => None,
}
}

pub fn on_definition_local(
local_url: &str,
store: &HashMap<String, String>,
) -> Option<LSPLocation> {
let local_url = local_url.trim_start_matches('.');

store
.keys()
.find(|uri| uri.ends_with(local_url))
.map(|uri| LSPLocation {
uri: uri.clone(),
range: Range {
start: LSPPosition {
line: 0,
character: 0,
},
end: LSPPosition {
line: 0,
character: 0,
},
},
})
}

pub fn on_definition_remote(
remote_url: &str,
store: &HashMap<String, String>,
) -> Option<LSPLocation> {
let path_hash = parser_utils::ParserUtils::remote_path_to_hash(remote_url);

store
.keys()
.find(|uri| uri.ends_with(format!("_{path_hash}.yaml").as_str()))
.map(|uri| LSPLocation {
uri: uri.clone(),
range: Range {
start: LSPPosition {
line: 0,
character: 0,
},
end: LSPPosition {
line: 0,
character: 0,
},
},
})
}

pub fn on_completion(&self, request: Request) -> Option<LSPResult> {
let start = Instant::now();
let params: CompletionParams = serde_json::from_value(request.params).ok()?;
Expand Down
1 change: 1 addition & 0 deletions src/gitlab_ci_ls_parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ pub struct IncludeInformation {
pub remote: Option<RemoteInclude>,
pub remote_url: Option<Include>,
pub local: Option<Include>,
pub basic: Option<Include>,
}

#[derive(Debug)]
Expand Down
104 changes: 68 additions & 36 deletions src/gitlab_ci_ls_parser/parser.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::HashMap;

use anyhow::anyhow;
use log::error;
use log::{error, info};
use lsp_types::{Position, Url};
use serde::{Deserialize, Serialize};

Expand All @@ -20,6 +20,7 @@ enum IncludeItem {
Project(Project),
Local(Local),
Remote(Remote),
Basic(String),
}

#[derive(Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -219,6 +220,55 @@ impl ParserImpl {
);
}
}

fn parse_remote_file(&self, remote_url: &str, parse_results: &mut ParseResults) {
let remote_url = match Url::parse(remote_url) {
Ok(f) => f,
Err(err) => {
error!(
"could not parse remote URL: {}; got err: {:?}",
remote_url, err
);

return;
}
};
let file = match self.git.fetch_remote(remote_url.clone()) {
Ok(res) => res,
Err(err) => {
error!(
"error retrieving remote file: {}; got err: {:?}",
remote_url, err
);

return;
}
};

self.parse_remote_files(parse_results, &[file]);
}

fn parse_local_file(
&self,
uri: &Url,
local_url: &str,
follow: bool,
parse_results: &mut ParseResults,
iteration: i32,
) -> Option<()> {
let current_uri = uri.join(local_url).ok()?;
let current_content = std::fs::read_to_string(current_uri.path()).ok()?;
if follow {
self.parse_contents_recursive(
parse_results,
&current_uri,
&current_content,
follow,
iteration + 1,
);
};
Some(())
}
}

impl Parser for ParserImpl {
Expand Down Expand Up @@ -313,43 +363,25 @@ impl Parser for ParserImpl {
for include_node in include_node.include {
match include_node {
IncludeItem::Local(node) => {
let current_uri = uri.join(node.local.as_str()).ok()?;
let current_content = std::fs::read_to_string(current_uri.path()).ok()?;

if follow {
self.parse_contents_recursive(
parse_results,
&current_uri,
&current_content,
follow,
iteration + 1,
);
}
self.parse_local_file(uri, &node.local, follow, parse_results, iteration)?;
}
IncludeItem::Remote(node) => {
let remote_url = match Url::parse(&node.remote) {
Ok(f) => f,
Err(err) => {
error!(
"could not parse remote URL: {}; got err: {:?}",
node.remote, err
);
continue;
}
};

let file = match self.git.fetch_remote(remote_url.clone()) {
Ok(res) => res,
Err(err) => {
error!(
"error retrieving remote file: {}; got err: {:?}",
remote_url, err
);
continue;
}
};

self.parse_remote_files(parse_results, &[file]);
self.parse_remote_file(&node.remote, parse_results);
}
IncludeItem::Basic(include_url) => {
if let Ok(url) = Url::parse(&include_url) {
info!("got remote URL: {url}");
self.parse_remote_file(url.as_str(), parse_results);
} else {
info!("got local URL: {include_url}");
self.parse_local_file(
uri,
&include_url,
follow,
parse_results,
iteration,
)?;
}
}
IncludeItem::Project(node) => {
let remote_files = match self.git.fetch_remote_repository(
Expand Down
12 changes: 12 additions & 0 deletions src/gitlab_ci_ls_parser/treesitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ impl Treesitter for TreesitterImpl {
let project_name_index = query.capture_index_for_name("project_value").unwrap();
let project_ref_index = query.capture_index_for_name("ref_value").unwrap();
let project_file_index = query.capture_index_for_name("file_value").unwrap();
let basic_include_index = query.capture_index_for_name("basic_include_value").unwrap();

for mat in matches {
// If this is a remote reference capture, I need to capture multiple values
Expand Down Expand Up @@ -467,6 +468,14 @@ impl Treesitter for TreesitterImpl {
..Default::default()
})
}
idx if idx == basic_include_index => {
return parser::PositionType::Include(IncludeInformation {
basic: Some(Include {
path: content[c.node.byte_range()].to_string(),
}),
..Default::default()
})
}
_ => {
error!("invalid index: {}", c.index);

Expand Down Expand Up @@ -1357,6 +1366,7 @@ job_one:
}),
local: None,
remote_url: None,
basic: None,
}) => {
assert_eq!(want_project, project);
assert_eq!(want_reference, reference);
Expand Down Expand Up @@ -1403,6 +1413,7 @@ job_one:
remote: None,
local: Some(Include { path }),
remote_url: None,
basic: None,
}) => {
assert_eq!(want_path, path);
}
Expand Down Expand Up @@ -1447,6 +1458,7 @@ job_one:
remote: None,
local: None,
remote_url: Some(Include { path }),
basic: None,
}) => {
assert_eq!(want_path, path);
}
Expand Down
26 changes: 26 additions & 0 deletions src/gitlab_ci_ls_parser/treesitter_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,31 @@ impl TreesitterQueries {
)
"#;

let search_basic_include = r#"
(
stream(
document(
block_node(
block_mapping(
block_mapping_pair
key: (flow_node(plain_scalar(string_scalar)@basic_include_key))
value: (
block_node(
block_sequence(
block_sequence_item(
flow_node
) @basic_include_value
)
)
)
)
)
)
)
(#eq? @local_include_key "include")
)
"#;

let search_project_includes = r#"
(
stream(
Expand Down Expand Up @@ -464,6 +489,7 @@ impl TreesitterQueries {
{search_project_includes}
{search_job_needs}
{search_remote_urls}
{search_basic_include}
"#
)
}
Expand Down

0 comments on commit 3f22d24

Please sign in to comment.