apollo-language-server 0.6.0

A GraphQL language server with first-class support for Apollo Federation
Documentation
pub const LEGEND_TYPE: &[lsp::SemanticTokenType] = &[
    lsp::SemanticTokenType::PROPERTY,
    lsp::SemanticTokenType::OPERATOR,
    lsp::SemanticTokenType::STRING,
    lsp::SemanticTokenType::NUMBER,
];

#[derive(Debug)]
pub struct IncompleteSemanticToken {
    pub range: lsp::Range,
    pub token_type: u32,
}

// Tokens are interpreted by the editor as a collection of 5 digits which make up a delta.
// The structure of the delta is as follows:
//   - The first digit is the delta_line, the line relative to the previous token
//   - The second digit is the delta_start, the character relative to the previous token if it is on the same line as another token or 0 if it is on its own
//   - The third digit is the length of the token
//   - The fourth digit is the token type
//   - The fifth digit is the token modifiers (this will always be 0 since we aren't using it)
// For more info see: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens:~:text=relative%27%3B-,Integer%20Encoding%20for%20Tokens,-On%20the%20capability
pub fn incomplete_tokens_to_deltas(
    tokens: Vec<IncompleteSemanticToken>,
) -> Vec<lsp::SemanticToken> {
    let mut tokens = tokens;

    tokens.sort_unstable_by_key(|token| (token.range.start.line, token.range.start.character));

    let mut prev_line = 0;
    let mut prev_start = 0;
    tokens
        .iter()
        .map(|token| {
            let start_line = token.range.start.line;
            let start_char = token.range.start.character;
            let length = token.range.end.character - token.range.start.character;

            let delta_line = start_line - prev_line;
            let delta_start = if delta_line == 0 {
                start_char - prev_start
            } else {
                start_char
            };
            prev_line = start_line;
            prev_start = start_char;

            lsp::SemanticToken {
                delta_line,
                delta_start,
                length,
                token_type: token.token_type,
                token_modifiers_bitset: 0,
            }
        })
        .collect::<Vec<_>>()
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_incomplete_tokens_to_deltas() {
        let tokens = vec![
            IncompleteSemanticToken {
                range: lsp::Range {
                    start: lsp::Position {
                        line: 0,
                        character: 0,
                    },
                    end: lsp::Position {
                        line: 0,
                        character: 3,
                    },
                },
                token_type: 0,
            },
            IncompleteSemanticToken {
                range: lsp::Range {
                    start: lsp::Position {
                        line: 0,
                        character: 3,
                    },
                    end: lsp::Position {
                        line: 0,
                        character: 4,
                    },
                },
                token_type: 1,
            },
            IncompleteSemanticToken {
                range: lsp::Range {
                    start: lsp::Position {
                        line: 1,
                        character: 0,
                    },
                    end: lsp::Position {
                        line: 1,
                        character: 3,
                    },
                },
                token_type: 0,
            },
        ];

        let expected = vec![
            lsp::SemanticToken {
                delta_line: 0,
                delta_start: 0,
                length: 3,
                token_type: 0,
                token_modifiers_bitset: 0,
            },
            lsp::SemanticToken {
                delta_line: 0,
                delta_start: 3,
                length: 1,
                token_type: 1,
                token_modifiers_bitset: 0,
            },
            lsp::SemanticToken {
                delta_line: 1,
                delta_start: 0,
                length: 3,
                token_type: 0,
                token_modifiers_bitset: 0,
            },
        ];

        assert_eq!(incomplete_tokens_to_deltas(tokens), expected);
    }

    #[test]
    fn test_unordered_incomplete_tokens_to_deltas() {
        let tokens = vec![
            IncompleteSemanticToken {
                range: lsp::Range {
                    start: lsp::Position {
                        line: 1,
                        character: 0,
                    },
                    end: lsp::Position {
                        line: 1,
                        character: 3,
                    },
                },
                token_type: 0,
            },
            IncompleteSemanticToken {
                range: lsp::Range {
                    start: lsp::Position {
                        line: 0,
                        character: 3,
                    },
                    end: lsp::Position {
                        line: 0,
                        character: 4,
                    },
                },
                token_type: 1,
            },
            IncompleteSemanticToken {
                range: lsp::Range {
                    start: lsp::Position {
                        line: 0,
                        character: 0,
                    },
                    end: lsp::Position {
                        line: 0,
                        character: 3,
                    },
                },
                token_type: 0,
            },
        ];

        let expected = vec![
            lsp::SemanticToken {
                delta_line: 0,
                delta_start: 0,
                length: 3,
                token_type: 0,
                token_modifiers_bitset: 0,
            },
            lsp::SemanticToken {
                delta_line: 0,
                delta_start: 3,
                length: 1,
                token_type: 1,
                token_modifiers_bitset: 0,
            },
            lsp::SemanticToken {
                delta_line: 1,
                delta_start: 0,
                length: 3,
                token_type: 0,
                token_modifiers_bitset: 0,
            },
        ];

        assert_eq!(incomplete_tokens_to_deltas(tokens), expected);
    }
}