142 lines
2.8 KiB
Go
142 lines
2.8 KiB
Go
|
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)
|
||
|
}
|