emmylua_ls 0.4.2

A language server for emmylua.
use emmylua_parser::{
    LuaAstNode, LuaDoStat, LuaForRangeStat, LuaForStat, LuaFuncStat, LuaIfStat, LuaLocalFuncStat,
    LuaRepeatStat, LuaWhileStat,
};
use lsp_types::{FoldingRange, FoldingRangeKind};
use rowan::TextRange;

use super::builder::FoldingRangeBuilder;

pub fn build_for_stat_fold_range(
    builder: &mut FoldingRangeBuilder,
    for_stat: LuaForStat,
) -> Option<()> {
    let range = for_stat.get_range();
    let document = builder.get_document();
    let lsp_range = document.to_lsp_range(range)?;
    if lsp_range.start.line == lsp_range.end.line {
        return None;
    }

    let folding_range = FoldingRange {
        start_line: lsp_range.start.line,
        start_character: Some(lsp_range.start.character),
        end_line: lsp_range.end.line - 1,
        end_character: Some(lsp_range.end.character),
        kind: Some(FoldingRangeKind::Region),
        collapsed_text: Some("fori .. end".to_string()),
    };

    builder.push(folding_range);
    Some(())
}

pub fn build_for_range_stat_fold_range(
    builder: &mut FoldingRangeBuilder,
    for_range_stat: LuaForRangeStat,
) -> Option<()> {
    let range = for_range_stat.get_range();
    let document = builder.get_document();
    let lsp_range = document.to_lsp_range(range)?;
    if lsp_range.start.line == lsp_range.end.line {
        return None;
    }

    let folding_range = FoldingRange {
        start_line: lsp_range.start.line,
        start_character: Some(lsp_range.start.character),
        end_line: lsp_range.end.line - 1,
        end_character: Some(lsp_range.end.character),
        kind: Some(FoldingRangeKind::Region),
        collapsed_text: Some("for .. end".to_string()),
    };

    builder.push(folding_range);
    Some(())
}

pub fn build_while_stat_fold_range(
    builder: &mut FoldingRangeBuilder,
    while_stat: LuaWhileStat,
) -> Option<()> {
    let range = while_stat.get_range();
    let document = builder.get_document();
    let lsp_range = document.to_lsp_range(range)?;
    if lsp_range.start.line == lsp_range.end.line {
        return None;
    }

    let folding_range = FoldingRange {
        start_line: lsp_range.start.line,
        start_character: Some(lsp_range.start.character),
        end_line: lsp_range.end.line - 1,
        end_character: Some(lsp_range.end.character),
        kind: Some(FoldingRangeKind::Region),
        collapsed_text: Some("while .. end".to_string()),
    };

    builder.push(folding_range);
    Some(())
}

pub fn build_repeat_stat_fold_range(
    builder: &mut FoldingRangeBuilder,
    repeat_stat: LuaRepeatStat,
) -> Option<()> {
    let range = repeat_stat.get_range();
    let document = builder.get_document();
    let lsp_range = document.to_lsp_range(range)?;
    if lsp_range.start.line == lsp_range.end.line {
        return None;
    }

    let folding_range = FoldingRange {
        start_line: lsp_range.start.line,
        start_character: Some(lsp_range.start.character),
        end_line: lsp_range.end.line - 1,
        end_character: Some(lsp_range.end.character),
        kind: Some(FoldingRangeKind::Region),
        collapsed_text: Some("repeat .. until".to_string()),
    };

    builder.push(folding_range);
    Some(())
}

pub fn build_do_stat_fold_range(
    builder: &mut FoldingRangeBuilder,
    do_stat: LuaDoStat,
) -> Option<()> {
    let range = do_stat.get_range();
    let document = builder.get_document();
    let lsp_range = document.to_lsp_range(range)?;
    if lsp_range.start.line == lsp_range.end.line {
        return None;
    }

    let folding_range = FoldingRange {
        start_line: lsp_range.start.line,
        start_character: Some(lsp_range.start.character),
        end_line: lsp_range.end.line - 1,
        end_character: Some(lsp_range.end.character),
        kind: Some(FoldingRangeKind::Region),
        collapsed_text: Some("do .. end".to_string()),
    };

    builder.push(folding_range);
    Some(())
}

pub fn build_local_func_stat_fold_range(
    builder: &mut FoldingRangeBuilder,
    local_func: LuaLocalFuncStat,
) -> Option<()> {
    let range = local_func.get_range();
    let document = builder.get_document();
    let lsp_range = document.to_lsp_range(range)?;
    if lsp_range.start.line == lsp_range.end.line {
        return None;
    }

    let func_name = local_func.get_local_name()?;
    let func_name_text = func_name.syntax().text().to_string();

    let folding_range = FoldingRange {
        start_line: lsp_range.start.line,
        start_character: Some(lsp_range.start.character),
        end_line: lsp_range.end.line - 1,
        end_character: Some(lsp_range.end.character),
        kind: Some(FoldingRangeKind::Region),
        collapsed_text: Some(format!("local function {} .. end", func_name_text)),
    };

    builder.push(folding_range);
    Some(())
}

pub fn build_func_stat_fold_range(
    builder: &mut FoldingRangeBuilder,
    func: LuaFuncStat,
) -> Option<()> {
    let range = func.get_range();
    let document = builder.get_document();
    let lsp_range = document.to_lsp_range(range)?;
    if lsp_range.start.line == lsp_range.end.line {
        return None;
    }

    let func_name = func.get_func_name()?;
    let func_name_text = func_name.syntax().text().to_string();

    let folding_range = FoldingRange {
        start_line: lsp_range.start.line,
        start_character: Some(lsp_range.start.character),
        end_line: lsp_range.end.line - 1,
        end_character: Some(lsp_range.end.character),
        kind: Some(FoldingRangeKind::Region),
        collapsed_text: Some(format!("function {} .. end", func_name_text)),
    };

    builder.push(folding_range);
    Some(())
}

pub fn build_if_stat_fold_range(
    builder: &mut FoldingRangeBuilder,
    if_stat: LuaIfStat,
) -> Option<()> {
    let mut branch_positions = Vec::new();
    let if_start_position = if_stat.get_position();
    branch_positions.push(if_start_position);
    for branch in if_stat.get_all_clause() {
        let branch_position = branch.get_position();
        branch_positions.push(branch_position);
    }
    let end_position = if_stat.get_range().end();
    branch_positions.push(end_position);

    let len = branch_positions.len() - 1;
    for i in 0..len {
        let start = branch_positions[i];
        let end = branch_positions[i + 1];
        let range = TextRange::new(start, end);
        let lsp_range = builder.get_document().to_lsp_range(range)?;
        if lsp_range.start.line == lsp_range.end.line {
            continue;
        }

        let folding_range = FoldingRange {
            start_line: lsp_range.start.line,
            start_character: Some(lsp_range.start.character),
            end_line: lsp_range.end.line - 1,
            end_character: Some(lsp_range.end.character),
            kind: Some(FoldingRangeKind::Region),
            collapsed_text: None,
        };

        builder.push(folding_range);
    }

    Some(())
}