Skip to main content
Glama

MCP Language Server

utilities.go4.47 kB
package tools import ( "fmt" "os" "sort" "strconv" "strings" "github.com/isaacphi/mcp-language-server/internal/protocol" ) func ExtractTextFromLocation(loc protocol.Location) (string, error) { path := strings.TrimPrefix(string(loc.URI), "file://") content, err := os.ReadFile(path) if err != nil { return "", fmt.Errorf("failed to read file: %w", err) } lines := strings.Split(string(content), "\n") startLine := int(loc.Range.Start.Line) endLine := int(loc.Range.End.Line) if startLine < 0 || startLine >= len(lines) || endLine < 0 || endLine >= len(lines) { return "", fmt.Errorf("invalid Location range: %v", loc.Range) } // Handle single-line case if startLine == endLine { line := lines[startLine] startChar := int(loc.Range.Start.Character) endChar := int(loc.Range.End.Character) if startChar < 0 || startChar > len(line) || endChar < 0 || endChar > len(line) { return "", fmt.Errorf("invalid character range: %v", loc.Range) } return line[startChar:endChar], nil } // Handle multi-line case var result strings.Builder // First line firstLine := lines[startLine] startChar := int(loc.Range.Start.Character) if startChar < 0 || startChar > len(firstLine) { return "", fmt.Errorf("invalid start character: %v", loc.Range.Start) } result.WriteString(firstLine[startChar:]) // Middle lines for i := startLine + 1; i < endLine; i++ { result.WriteString("\n") result.WriteString(lines[i]) } // Last line lastLine := lines[endLine] endChar := int(loc.Range.End.Character) if endChar < 0 || endChar > len(lastLine) { return "", fmt.Errorf("invalid end character: %v", loc.Range.End) } result.WriteString("\n") result.WriteString(lastLine[:endChar]) return result.String(), nil } func containsPosition(r protocol.Range, p protocol.Position) bool { if r.Start.Line > p.Line || r.End.Line < p.Line { return false } if r.Start.Line == p.Line && r.Start.Character > p.Character { return false } if r.End.Line == p.Line && r.End.Character <= p.Character { return false } return true } // addLineNumbers adds line numbers to each line of text with proper padding, starting from startLine func addLineNumbers(text string, startLine int) string { lines := strings.Split(text, "\n") // Calculate padding width based on the number of digits in the last line number lastLineNum := startLine + len(lines) padding := len(strconv.Itoa(lastLineNum)) var result strings.Builder for i, line := range lines { // Format line number with padding and separator lineNum := strconv.Itoa(startLine + i) linePadding := strings.Repeat(" ", padding-len(lineNum)) result.WriteString(fmt.Sprintf("%s%s|%s\n", linePadding, lineNum, line)) } return result.String() } // LineRange represents a continuous range of lines to display type LineRange struct { Start int End int } // ConvertLinesToRanges converts a set of lines to continuous ranges func ConvertLinesToRanges(linesToShow map[int]bool, totalLines int) []LineRange { // Convert map to sorted slice lineNumbers := make([]int, 0, len(linesToShow)) for line := range linesToShow { if line >= 0 && line < totalLines { lineNumbers = append(lineNumbers, line) } } sort.Ints(lineNumbers) // Group into ranges var ranges []LineRange if len(lineNumbers) == 0 { return ranges } currentRange := LineRange{Start: lineNumbers[0], End: lineNumbers[0]} for i := 1; i < len(lineNumbers); i++ { if lineNumbers[i] == currentRange.End+1 { // Extend current range currentRange.End = lineNumbers[i] } else { // Start new range ranges = append(ranges, currentRange) currentRange = LineRange{Start: lineNumbers[i], End: lineNumbers[i]} } } // Add the last range ranges = append(ranges, currentRange) return ranges } // FormatLinesWithRanges formats file content using line ranges func FormatLinesWithRanges(lines []string, ranges []LineRange) string { if len(ranges) == 0 { return "" } var result strings.Builder lastEnd := -1 for _, r := range ranges { // Add skipped lines indicator if lastEnd != -1 && r.Start > lastEnd+1 { // skipped := r.Start - lastEnd - 1 result.WriteString("...\n") } // Extract lines for this range rangeLines := lines[r.Start : r.End+1] // Add line numbers using the existing function numberedText := addLineNumbers(strings.Join(rangeLines, "\n"), r.Start+1) result.WriteString(numberedText) lastEnd = r.End } return result.String() }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/isaacphi/mcp-language-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server