wide/vendor/github.com/nsf/gocode/ripper.go

142 lines
2.8 KiB
Go
Raw Normal View History

2018-03-13 07:10:52 +03:00
package main
import (
"go/scanner"
"go/token"
)
// All the code in this file serves single purpose:
// It separates a function with the cursor inside and the rest of the code. I'm
// doing that, because sometimes parser is not able to recover itself from an
// error and the autocompletion results become less complete.
type tok_pos_pair struct {
tok token.Token
pos token.Pos
}
type tok_collection struct {
tokens []tok_pos_pair
fset *token.FileSet
}
func (this *tok_collection) next(s *scanner.Scanner) bool {
pos, tok, _ := s.Scan()
if tok == token.EOF {
return false
}
this.tokens = append(this.tokens, tok_pos_pair{tok, pos})
return true
}
func (this *tok_collection) find_decl_beg(pos int) int {
lowest := 0
lowpos := -1
lowi := -1
cur := 0
for i := pos; i >= 0; i-- {
t := this.tokens[i]
switch t.tok {
case token.RBRACE:
cur++
case token.LBRACE:
cur--
}
if cur < lowest {
lowest = cur
lowpos = this.fset.Position(t.pos).Offset
lowi = i
}
}
cur = lowest
for i := lowi - 1; i >= 0; i-- {
t := this.tokens[i]
switch t.tok {
case token.RBRACE:
cur++
case token.LBRACE:
cur--
}
if t.tok == token.SEMICOLON && cur == lowest {
lowpos = this.fset.Position(t.pos).Offset
break
}
}
return lowpos
}
func (this *tok_collection) find_decl_end(pos int) int {
highest := 0
highpos := -1
cur := 0
if this.tokens[pos].tok == token.LBRACE {
pos++
}
for i := pos; i < len(this.tokens); i++ {
t := this.tokens[i]
switch t.tok {
case token.RBRACE:
cur++
case token.LBRACE:
cur--
}
if cur > highest {
highest = cur
highpos = this.fset.Position(t.pos).Offset
}
}
return highpos
}
func (this *tok_collection) find_outermost_scope(cursor int) (int, int) {
pos := 0
for i, t := range this.tokens {
if cursor <= this.fset.Position(t.pos).Offset {
break
}
pos = i
}
return this.find_decl_beg(pos), this.find_decl_end(pos)
}
// return new cursor position, file without ripped part and the ripped part itself
// variants:
// new-cursor, file-without-ripped-part, ripped-part
// old-cursor, file, nil
func (this *tok_collection) rip_off_decl(file []byte, cursor int) (int, []byte, []byte) {
this.fset = token.NewFileSet()
var s scanner.Scanner
s.Init(this.fset.AddFile("", this.fset.Base(), len(file)), file, nil, scanner.ScanComments)
for this.next(&s) {
}
beg, end := this.find_outermost_scope(cursor)
if beg == -1 || end == -1 {
return cursor, file, nil
}
ripped := make([]byte, end+1-beg)
copy(ripped, file[beg:end+1])
newfile := make([]byte, len(file)-len(ripped))
copy(newfile, file[:beg])
copy(newfile[beg:], file[end+1:])
return cursor - beg, newfile, ripped
}
func rip_off_decl(file []byte, cursor int) (int, []byte, []byte) {
var tc tok_collection
return tc.rip_off_decl(file, cursor)
}