1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
use rnix::{
ast::Ident,
NixLanguage, SyntaxKind,
};
use rowan::{api::SyntaxNode, ast::AstNode};
/// This string in a Nix comment above an unused declaration shall
/// force us to skip it.
///
/// ```nix
/// let
/// # deadnix: skip
/// skeletonsInTheBasement =
/// ```
const PRAGMA_SKIP: &str = "deadnix: skip";
/// A Nix variable binding
#[derive(Debug, Clone)]
pub struct Binding {
/// Variable name
pub name: Ident,
/// Syntax node of declaration itself
pub decl_node: SyntaxNode<NixLanguage>,
mortal: bool,
}
impl Binding {
/// Create a new Binding
pub fn new(
name: Ident,
decl_node: SyntaxNode<NixLanguage>,
mortal: bool,
) -> Self {
Binding {
name,
decl_node,
mortal,
}
}
/// Can die?
///
/// Not mortal are `rec { ... }`, and lambda args that already
/// start with `_`.
pub fn is_mortal(&self) -> bool {
self.mortal
}
/// Does the name start with `_`, signifying an anonymous
/// variable?
pub fn starts_with_underscore(&self) -> bool {
self.name.syntax().text().char_at(0.into()) == Some('_')
}
/// Searches through tokens backwards for `PRAGMA_SKIP` until at
/// least two linebreaks are seen
pub fn has_pragma_skip(&self) -> bool {
let mut line_breaks = 0;
let mut token = self.decl_node.first_token().unwrap();
while let Some(prev) = token.prev_token() {
token = prev;
match token.kind() {
SyntaxKind::TOKEN_WHITESPACE => {
line_breaks += token.text().matches('\n').count();
if line_breaks > 1 {
break;
}
}
SyntaxKind::TOKEN_COMMENT if token.text().contains(PRAGMA_SKIP) =>
return true,
_ => {}
}
}
// No PRAGMA_SKIP found
false
}
}