cairo-language-server 2.20.0

The Cairo Language Server
Documentation
use cairo_lang_defs::ids::LookupItemId::ModuleItem;
use cairo_lang_defs::ids::{ModuleId, ModuleItemId};
use cairo_lang_doc::db::DocGroup;
use cairo_lang_doc::documentable_item::DocumentableItemId;
use cairo_lang_semantic::corelib::CorelibSemantic;
use cairo_lang_semantic::helper::ModuleHelper;
use cairo_lang_syntax::node::kind::SyntaxKind;

use crate::ide::markdown::{RULE, fenced_code_block};
use crate::lang::db::AnalysisDatabase;

pub fn keyword(db: &AnalysisDatabase, kind: SyntaxKind) -> Option<String> {
    let keyword = CairoKeyword::try_from_kind(&kind)?;
    let keyword_docs = keyword.get_docs(db)?;

    let mut md = String::new();

    md += &fenced_code_block(keyword.token.as_str());
    md += RULE;
    md += "\n";

    md += &keyword_docs;

    Some(md)
}

struct CairoKeyword {
    mod_name: String,
    token: String,
}

impl CairoKeyword {
    fn try_from_kind(kind: &SyntaxKind) -> Option<Self> {
        if !kind.is_keyword_token() {
            return None;
        }

        let keyword = keyword_token_from_kind(kind);
        let mod_name = format!("keyword_{}", keyword);

        Some(Self { mod_name, token: keyword.to_string() })
    }

    fn get_docs(&self, db: &AnalysisDatabase) -> Option<String> {
        let core_info_struct = db.core_info();
        let keywords_module_id = core_info_struct.keyword_docs_submodule;

        let keyword_submodule =
            ModuleHelper { db, id: keywords_module_id }.submodule(&self.mod_name).id;

        let ModuleId::Submodule(keyword_submodule_id) = keyword_submodule else {
            panic!("Could not find keyword submodule: {}", self.mod_name);
        };

        db.get_item_documentation(DocumentableItemId::LookupItem(ModuleItem(
            ModuleItemId::Submodule(keyword_submodule_id),
        )))
    }
}

fn keyword_token_from_kind(kind: &SyntaxKind) -> &str {
    match kind {
        SyntaxKind::TokenAs => "as",
        SyntaxKind::TokenConst => "const",
        SyntaxKind::TokenElse => "else",
        SyntaxKind::TokenEnum => "enum",
        SyntaxKind::TokenExtern => "extern",
        SyntaxKind::TokenFalse => "false",
        SyntaxKind::TokenFunction => "fn",
        SyntaxKind::TokenIf => "if",
        SyntaxKind::TokenWhile => "while",
        SyntaxKind::TokenFor => "for",
        SyntaxKind::TokenLoop => "loop",
        SyntaxKind::TokenImpl => "impl",
        SyntaxKind::TokenImplicits => "implicits",
        SyntaxKind::TokenLet => "let",
        SyntaxKind::TokenMacro => "macro",
        SyntaxKind::TokenMatch => "match",
        SyntaxKind::TokenModule => "mod",
        SyntaxKind::TokenMut => "mut",
        SyntaxKind::TokenNoPanic => "nopanic",
        SyntaxKind::TokenOf => "of",
        SyntaxKind::TokenRef => "ref",
        SyntaxKind::TokenContinue => "continue",
        SyntaxKind::TokenReturn => "return",
        SyntaxKind::TokenBreak => "break",
        SyntaxKind::TokenStruct => "struct",
        SyntaxKind::TokenTrait => "trait",
        SyntaxKind::TokenTrue => "true",
        SyntaxKind::TokenType => "type",
        SyntaxKind::TokenUse => "use",
        SyntaxKind::TokenPub => "pub",
        _ => panic!("Unknown keyword kind: {:?}", kind),
    }
}