C# Lang MCP Server
by biegehydra
- src
import * as vscode from 'vscode';
export interface DocumentSymbolResult {
name: string;
detail: string;
kind: vscode.SymbolKind;
range: {
start: { line: number; character: number };
end: { line: number; character: number };
};
selectionRange: {
start: { line: number; character: number };
end: { line: number; character: number };
};
children: DocumentSymbolResult[];
}
export function convertSymbol(symbol: vscode.DocumentSymbol): DocumentSymbolResult {
return {
name: symbol.name,
detail: symbol.detail,
kind: symbol.kind,
range: {
start: {
line: symbol.range.start.line,
character: symbol.range.start.character
},
end: {
line: symbol.range.end.line,
character: symbol.range.end.character
}
},
selectionRange: {
start: {
line: symbol.selectionRange.start.line,
character: symbol.selectionRange.start.character
},
end: {
line: symbol.selectionRange.end.line,
character: symbol.selectionRange.end.character
}
},
children: symbol.children.map(convertSymbol)
};
}
export async function getPreview(uri: vscode.Uri, line: number | undefined): Promise<string> {
if (!line) {
return "";
}
const document = await vscode.workspace.openTextDocument(uri);
const lineText = document.lineAt(line).text.trim();
return lineText;
}
export function createVscodePosition(line: number, character: number): vscode.Position | undefined {
if (!line) {
return undefined;
}
if (!character) {
return undefined;
}
return new vscode.Position(
line - 1,
character
);
}
export async function asyncMap<T, R>(array: T[], asyncCallback: (item: T) => Promise<R>): Promise<R[]> {
return Promise.all(array.map(asyncCallback));
}
export function convertSemanticTokens(semanticTokens: vscode.SemanticTokens, document: vscode.TextDocument): any {
const tokens: any[] = [];
let prevLine = 0;
let prevChar = 0;
// Token types and modifiers from VS Code
const tokenTypes = [
'namespace', 'type', 'class', 'enum', 'interface',
'struct', 'typeParameter', 'parameter', 'variable', 'property',
'enumMember', 'event', 'function', 'method', 'macro',
'keyword', 'modifier', 'comment', 'string', 'number',
'regexp', 'operator', 'decorator'
];
const tokenModifiers = [
'declaration', 'definition', 'readonly', 'static',
'deprecated', 'abstract', 'async', 'modification',
'documentation', 'defaultLibrary'
];
// Process tokens in groups of 5 (format: deltaLine, deltaStartChar, length, tokenType, tokenModifiers)
for (let i = 0; i < semanticTokens.data.length; i += 5) {
const deltaLine = semanticTokens.data[i];
const deltaStartChar = semanticTokens.data[i + 1];
const length = semanticTokens.data[i + 2];
const tokenType = tokenTypes[semanticTokens.data[i + 3]] || 'unknown';
const tokenModifiersBitset = semanticTokens.data[i + 4];
// Calculate absolute position
const line = prevLine + deltaLine;
const startChar = deltaLine === 0 ? prevChar + deltaStartChar : deltaStartChar;
// Get the actual text content
const tokenText = document.lineAt(line).text.substr(startChar, length);
// Convert token modifiers bitset to array of strings
const modifiers = tokenModifiers.filter((_, index) => tokenModifiersBitset & (1 << index));
tokens.push({
line,
startCharacter: startChar,
length,
tokenType,
modifiers,
text: tokenText
});
prevLine = line;
prevChar = startChar;
}
return tokens;
}