all repos

clerk @ 9b2ce6b

missing tooling for ledger/hledger

clerk/internal/lsp/textdocument_format.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
lsp: move code around, 2 months ago
1
package lsp
2
3
import (
4
	"context"
5
	"fmt"
6
	"strings"
7
8
	"go.lsp.dev/protocol"
9
10
	"olexsmir.xyz/clerk/journal/lexer"
11
	"olexsmir.xyz/clerk/journal/parser"
12
)
13
14
func (s *server) Formatting(ctx context.Context, params *protocol.DocumentFormattingParams) ([]protocol.TextEdit, error) {
15
	state, ok := s.getDocState(params.TextDocument.URI)
16
	if !ok {
17
		return nil, nil
18
	}
19
20
	text := state.text
21
	lex := lexer.New(params.TextDocument.URI.Path(), []byte(text))
22
	jnrl := parser.New(lex).ParseJournal()
23
	if len(jnrl.Errors) > 0 {
24
		return nil, fmt.Errorf("can't format file with errors: %v", jnrl.Errors[0].Message) // TODO: report all errors
25
	}
26
27
	var buf strings.Builder
28
	if err := s.printer.Fprint(&buf, jnrl); err != nil {
29
		return nil, fmt.Errorf("format: %w", err)
30
	}
31
32
	newText := buf.String()
33
	if newText == text {
34
		return nil, nil
35
	}
36
37
	endLine, endChar := getEndLineAndChar(text)
38
	return []protocol.TextEdit{{
39
		NewText: newText,
40
		Range: protocol.Range{
41
			Start: protocol.Position{
42
				Line:      0,
43
				Character: 0,
44
			},
45
			End: protocol.Position{
46
				Line:      uint32(endLine),
47
				Character: uint32(endChar),
48
			},
49
		},
50
	}}, nil
51
}
52
53
func getEndLineAndChar(txt string) (int, int) {
54
	endLine := 0
55
	lastNewline := -1
56
	for i, ch := range txt {
57
		if ch == '\n' {
58
			endLine++
59
			lastNewline = i
60
		}
61
	}
62
	endChar := 0
63
	if lastNewline >= 0 {
64
		if lastNewline == len(txt)-1 {
65
			endLine++
66
			endChar = 0
67
		} else {
68
			endChar = len(txt) - lastNewline - 1
69
		}
70
	} else {
71
		endChar = len(txt)
72
	}
73
	return endLine, endChar
74
}