Skip to content

Commit

Permalink
refactor(internal/lsp): 合并相似代码
Browse files Browse the repository at this point in the history
  • Loading branch information
caixw committed Aug 31, 2020
1 parent 0f5dac4 commit f3fcb0a
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 157 deletions.
28 changes: 10 additions & 18 deletions internal/lsp/hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"reflect"

"github.com/caixw/apidoc/v7/core"
"github.com/caixw/apidoc/v7/internal/ast"
"github.com/caixw/apidoc/v7/internal/lsp/protocol"
)

Expand All @@ -17,22 +16,6 @@ type usager interface {

var usagerType = reflect.TypeOf((*usager)(nil)).Elem()

func hover(doc *ast.APIDoc, uri core.URI, pos core.Position, h *protocol.Hover) {
u := doc.Search(uri, pos, usagerType)
if u == nil {
return
}

usage := u.(usager)
if v := usage.Usage(); v != "" {
h.Range = usage.Loc().Range
h.Contents = protocol.MarkupContent{
Kind: protocol.MarkupKindMarkdown,
Value: v,
}
}
}

// textDocument/hover
//
// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
Expand All @@ -46,6 +29,15 @@ func (s *server) textDocumentHover(notify bool, in *protocol.HoverParams, out *p
f.parsedMux.RLock()
defer f.parsedMux.RUnlock()

hover(f.doc, in.TextDocument.URI, in.TextDocumentPositionParams.Position, out)
if u := f.doc.Search(in.TextDocument.URI, in.TextDocumentPositionParams.Position, usagerType); u != nil {
usage := u.(usager)
if v := usage.Usage(); v != "" {
out.Range = usage.Loc().Range
out.Contents = protocol.MarkupContent{
Kind: protocol.MarkupKindMarkdown,
Value: v,
}
}
}
return nil
}
76 changes: 8 additions & 68 deletions internal/lsp/hover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ import (
"github.com/caixw/apidoc/v7/internal/lsp/protocol"
)

func loadHoverDoc(a *assert.Assertion) *ast.APIDoc {
func TestServer_textDocumentHover(t *testing.T) {
a := assert.New(t)
s := newTestServer(true, log.New(ioutil.Discard, "", 0), log.New(ioutil.Discard, "", 0))
h := &protocol.Hover{}
err := s.textDocumentHover(false, &protocol.HoverParams{}, h)
a.Nil(err)

const b = `<apidoc version="1.1.1">
<title>标题</title>
<mimetype>xml</mimetype>
Expand All @@ -30,28 +36,17 @@ func loadHoverDoc(a *assert.Assertion) *ast.APIDoc {
<response status="200" />
</api>
</apidoc>`

blk := core.Block{Data: []byte(b), Location: core.Location{URI: "file:///test/doc.go"}}
rslt := messagetest.NewMessageHandler()
doc := &ast.APIDoc{}
doc.Parse(rslt.Handler, blk)
rslt.Handler.Stop()
a.Empty(rslt.Errors)

return doc
}

func TestServer_textDocumentHover(t *testing.T) {
a := assert.New(t)
s := newTestServer(true, log.New(ioutil.Discard, "", 0), log.New(ioutil.Discard, "", 0))
h := &protocol.Hover{}
err := s.textDocumentHover(false, &protocol.HoverParams{}, h)
a.Nil(err)

s.folders = []*folder{
{
WorkspaceFolder: protocol.WorkspaceFolder{Name: "test", URI: "file:///test"},
doc: loadHoverDoc(a),
doc: doc,
},
}

Expand All @@ -67,58 +62,3 @@ func TestServer_textDocumentHover(t *testing.T) {
})
a.Equal(h.Contents.Value, locale.Sprintf("usage-apidoc-title"))
}

func TestHover(t *testing.T) {
a := assert.New(t)

doc := loadHoverDoc(a)

// 超出范围
h := &protocol.Hover{}
pos := core.Position{Line: 1000, Character: 1}
hover(doc, core.URI("file:///test/doc.go"), pos, h)
a.True(h.Range.IsEmpty()).Empty(h.Contents.Value)

// title
h = &protocol.Hover{}
pos = core.Position{Line: 1, Character: 1}
hover(doc, core.URI("file:///test/doc.go"), pos, h)
a.Equal(h.Range, core.Range{
Start: core.Position{Line: 1, Character: 1},
End: core.Position{Line: 1, Character: 18},
})
a.Equal(h.Contents.Value, locale.Sprintf("usage-apidoc-title"))

// apis[0]
h = &protocol.Hover{}
pos = core.Position{Line: 4, Character: 2}
hover(doc, core.URI("file:///test/doc.go"), pos, h)
a.Equal(h.Range, core.Range{
Start: core.Position{Line: 4, Character: 1},
End: core.Position{Line: 7, Character: 7},
})
a.Equal(h.Contents.Value, locale.Sprintf("usage-apidoc-apis"))

// 改变了 api[0].URI
doc.APIs[0].URI = core.URI("api0.go")

// 改变了 api[0].URI,不再匹配 apis[0],取其父元素 apidoc
h = &protocol.Hover{}
pos = core.Position{Line: 4, Character: 1}
hover(doc, core.URI("file:///test/doc.go"), pos, h)
a.Equal(h.Range, core.Range{
Start: core.Position{Line: 0, Character: 0},
End: core.Position{Line: 12, Character: 9},
})
a.Equal(h.Contents.Value, locale.Sprintf("usage-apidoc"))

// 与 apis[0] 相同的 URI
h = &protocol.Hover{}
pos = core.Position{Line: 4, Character: 1}
hover(doc, core.URI("api0.go"), pos, h)
a.Equal(h.Range, core.Range{
Start: core.Position{Line: 4, Character: 1},
End: core.Position{Line: 7, Character: 7},
})
a.Equal(h.Contents.Value, locale.Sprintf("usage-apidoc-apis"))
}
13 changes: 3 additions & 10 deletions internal/lsp/reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ func (s *server) textDocumentDefinition(notify bool, in *protocol.DefinitionPara
f.parsedMux.RLock()
defer f.parsedMux.RUnlock()

*out = definition(f.doc, in.TextDocument.URI, in.Position)
if r := f.doc.Search(in.TextDocument.URI, in.TextDocumentPositionParams.Position, definitionerType); r != nil {
*out = []core.Location{r.(ast.Definitioner).Definition().Location}
}
return nil
}

Expand All @@ -67,12 +69,3 @@ func references(doc *ast.APIDoc, uri core.URI, pos core.Position, include bool)

return
}

func definition(doc *ast.APIDoc, uri core.URI, pos core.Position) []core.Location {
r := doc.Search(uri, pos, definitionerType)
if r == nil {
return []core.Location{}
}

return []core.Location{r.(ast.Definitioner).Definition().Location}
}
37 changes: 0 additions & 37 deletions internal/lsp/reference_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,40 +123,3 @@ func TestReferences(t *testing.T) {
locs = references(doc, "file:///root/doc.go", pos, true)
a.Equal(len(locs), 3)
}

func TestDefinition(t *testing.T) {
a := assert.New(t)
doc := loadReferencesDoc(a)

pos := core.Position{}
locs := definition(doc, "file:///root/doc.go", pos)
a.Empty(locs)

pos = core.Position{Line: 3, Character: 16}
locs = definition(doc, "file:///root/doc.go", pos)
a.Empty(locs)

pos = core.Position{Line: 6, Character: 2}
locs = definition(doc, "file:///root/doc.go", pos)
a.Equal(locs, []core.Location{
{
URI: "file:///root/doc.go",
Range: core.Range{
Start: core.Position{Line: 3, Character: 1},
End: core.Position{Line: 3, Character: 31},
},
},
})

pos = core.Position{Line: 12, Character: 2}
locs = definition(doc, "file:///root/doc.go", pos)
a.Equal(locs, []core.Location{
{
URI: "file:///root/doc.go",
Range: core.Range{
Start: core.Position{Line: 4, Character: 1},
End: core.Position{Line: 4, Character: 31},
},
},
})
}
20 changes: 10 additions & 10 deletions internal/xmlenc/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ func Decode(p *Parser, v interface{}, namespace string) {
switch elem := t.(type) {
case *StartElement:
if hasRoot { // 多个根元素
_ = p.endElement(elem) // 找到对应的结束标签,忽略错误
msg := p.NewError(elem.Location.Range.Start, p.Current().Position, elem.Name.String(), locale.ErrMultipleRootTag).
AddTypes(core.ErrorTypeUnused)
p.endElement(elem) // 找到对应的结束标签,忽略错误
msg := core.NewError(locale.ErrMultipleRootTag).AddTypes(core.ErrorTypeUnused).WithField(elem.Name.String()).
WithLocation(core.Location{URI: elem.URI, Range: core.Range{Start: elem.Location.Range.Start, End: p.Current().Position}})
d.p.Warning(msg)
return
}
Expand Down Expand Up @@ -155,19 +155,19 @@ func (d *decoder) decode(n *node.Node, start *StartElement) *EndElement {
func (d *decoder) checkOmitempty(n *node.Node, start, end core.Position, field string) {
for _, attr := range n.Attributes {
if canNotEmpty(attr) {
d.p.Error(d.p.NewError(start, end, attr.Name, locale.ErrIsEmpty, attr.Name))
d.p.Error(d.p.newError(start, end, attr.Name, locale.ErrIsEmpty, attr.Name))
}
}
for _, elem := range n.Elements {
if canNotEmpty(elem) {
d.p.Error(d.p.NewError(start, end, elem.Name, locale.ErrIsEmpty, elem.Name))
d.p.Error(d.p.newError(start, end, elem.Name, locale.ErrIsEmpty, elem.Name))
}
}
if n.CData != nil && canNotEmpty(n.CData) {
d.p.Error(d.p.NewError(start, end, "cdata", locale.ErrIsEmpty, field))
d.p.Error(d.p.newError(start, end, "cdata", locale.ErrIsEmpty, field))
}
if n.Content != nil && canNotEmpty(n.Content) {
d.p.Error(d.p.NewError(start, end, "content", locale.ErrIsEmpty, field))
d.p.Error(d.p.newError(start, end, "content", locale.ErrIsEmpty, field))
}
}

Expand Down Expand Up @@ -222,7 +222,7 @@ func (d *decoder) decodeElements(n *node.Node) (end *EndElement, ok bool) {
t, loc, err := d.p.Token()
if errors.Is(err, io.EOF) {
// 应该只有 EndElement 才能返回,否则就不完整的 XML
d.p.Error(d.p.NewError(d.p.Current().Position, d.p.Current().Position, "", locale.ErrNotFoundEndTag))
d.p.Error(d.p.newError(d.p.Current().Position, d.p.Current().Position, "", locale.ErrNotFoundEndTag))
return nil, false
} else if err != nil {
d.p.Error(err)
Expand All @@ -234,7 +234,7 @@ func (d *decoder) decodeElements(n *node.Node) (end *EndElement, ok bool) {
if (elem.Name.Local.Value == n.Value.Name) && (elem.Name.Prefix.Value == d.prefix) {
return elem, true
}
d.p.Error(d.p.NewError(elem.Location.Range.Start, elem.Location.Range.End, n.Value.Name, locale.ErrNotFoundEndTag))
d.p.Error(d.p.newError(elem.Location.Range.Start, elem.Location.Range.End, n.Value.Name, locale.ErrNotFoundEndTag))
return nil, false
case *CData:
if n.CData != nil {
Expand All @@ -252,7 +252,7 @@ func (d *decoder) decodeElements(n *node.Node) (end *EndElement, ok bool) {
return nil, false
}

e := d.p.NewError(elem.Location.Range.Start, d.p.Current().Position, elem.Name.String(), locale.ErrInvalidTag).
e := d.p.newError(elem.Location.Range.Start, d.p.Current().Position, elem.Name.String(), locale.ErrInvalidTag).
AddTypes(core.ErrorTypeUnused)
d.p.Warning(e)
break // 忽略不存在的子元素
Expand Down
26 changes: 12 additions & 14 deletions internal/xmlenc/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func (p *Parser) parseComment(pos lexer.Position) (*Comment, core.Location, erro

data, found := p.DelimString("-->", false)
if !found {
return nil, core.Location{}, p.NewError(p.Current().Position, p.Current().Position, "<!--", locale.ErrNotFoundEndTag)
return nil, core.Location{}, p.newError(p.Current().Position, p.Current().Position, "<!--", locale.ErrNotFoundEndTag)
}
end := p.Current()
p.Next(3) // 跳过 --> 三个字符
Expand All @@ -127,7 +127,7 @@ func (p *Parser) parseStartElement(pos lexer.Position) (*StartElement, core.Loca
start := p.Current()
name, found := p.DelimFunc(func(r rune) bool { return unicode.IsSpace(r) || r == '/' || r == '>' }, false)
if !found || len(name) == 0 {
return nil, core.Location{}, p.NewError(p.Current().Position, p.Current().Position, "", locale.ErrInvalidXML)
return nil, core.Location{}, p.newError(p.Current().Position, p.Current().Position, "", locale.ErrInvalidXML)
}

elem := &StartElement{
Expand All @@ -152,7 +152,7 @@ func (p *Parser) parseStartElement(pos lexer.Position) (*StartElement, core.Loca
return elem, elem.Location, nil
}

return nil, core.Location{}, p.NewError(p.Current().Position, p.Current().Position, string(name), locale.ErrNotFoundEndTag)
return nil, core.Location{}, p.newError(p.Current().Position, p.Current().Position, string(name), locale.ErrNotFoundEndTag)
}

func parseName(name []byte, uri core.URI, start, end core.Position) Name {
Expand Down Expand Up @@ -188,7 +188,7 @@ func (p *Parser) parseEndElement(pos lexer.Position) (*EndElement, core.Location

name, found := p.Delim('>', false)
if !found || len(name) == 0 {
return nil, core.Location{}, p.NewError(p.Current().Position, p.Current().Position, "", locale.ErrInvalidXML)
return nil, core.Location{}, p.newError(p.Current().Position, p.Current().Position, "", locale.ErrInvalidXML)
}
end := p.Current()
p.Next(1) // 去掉 > 符号
Expand All @@ -211,7 +211,7 @@ func (p *Parser) parseCData(pos lexer.Position) (*CData, core.Location, error) {
for {
v, found := p.DelimString(cdataEnd, false)
if !found {
return nil, core.Location{}, p.NewError(pos.Position, p.Current().Position, cdataStart, locale.ErrNotFoundEndTag)
return nil, core.Location{}, p.newError(pos.Position, p.Current().Position, cdataStart, locale.ErrNotFoundEndTag)
}
value = append(value, v...)

Expand Down Expand Up @@ -291,7 +291,7 @@ func (p *Parser) parseCData(pos lexer.Position) (*CData, core.Location, error) {
func (p *Parser) parseInstruction(pos lexer.Position) (*Instruction, core.Location, error) {
name, nameRange := p.getName()
if len(name) == 0 {
return nil, core.Location{}, p.NewError(p.Current().Position, p.Current().Position, "", locale.ErrInvalidXML)
return nil, core.Location{}, p.newError(p.Current().Position, p.Current().Position, "", locale.ErrInvalidXML)
}
elem := &Instruction{
Location: core.Location{URI: p.Location.URI},
Expand All @@ -316,7 +316,7 @@ func (p *Parser) parseInstruction(pos lexer.Position) (*Instruction, core.Locati
return elem, elem.Location, nil
}

return nil, core.Location{}, p.NewError(p.Current().Position, p.Current().Position, "<?", locale.ErrNotFoundEndTag)
return nil, core.Location{}, p.newError(p.Current().Position, p.Current().Position, "<?", locale.ErrNotFoundEndTag)
}

func (p *Parser) parseAttributes() (attrs []*Attribute, err error) {
Expand Down Expand Up @@ -351,18 +351,18 @@ func (p *Parser) parseAttribute() (*Attribute, error) {

p.Spaces(0)
if !p.Match("=") {
return nil, p.NewError(p.Current().Position, p.Current().Position, "", locale.ErrInvalidXML)
return nil, p.newError(p.Current().Position, p.Current().Position, "", locale.ErrInvalidXML)
}

p.Spaces(0)
if !p.Match("\"") {
return nil, p.NewError(p.Current().Position, p.Current().Position, "", locale.ErrInvalidXML)
return nil, p.newError(p.Current().Position, p.Current().Position, "", locale.ErrInvalidXML)
}

pos = p.Current()
value, found := p.Delim('"', true)
if !found || len(value) == 0 {
return nil, p.NewError(p.Current().Position, p.Current().Position, "", locale.ErrInvalidXML)
return nil, p.newError(p.Current().Position, p.Current().Position, "", locale.ErrInvalidXML)
}
end := p.Current().SubRune('"') // 不包含 " 符号
attr.Value = String{
Expand Down Expand Up @@ -438,10 +438,8 @@ func (p *Parser) endElement(start *StartElement) error {
}
}

// NewError 生成 *core.Error 对象
//
// 其中的 URI 来自于 p.Location.URI
func (p *Parser) NewError(start, end core.Position, field string, key message.Reference, v ...interface{}) *core.Error {
// newError 生成 *core.Error 对象,其中的 URI 来自于 p.Location.URI。
func (p *Parser) newError(start, end core.Position, field string, key message.Reference, v ...interface{}) *core.Error {
return core.NewError(key, v...).
WithField(field).
WithLocation(core.Location{
Expand Down

0 comments on commit f3fcb0a

Please sign in to comment.