101 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			101 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
// Copyright 2019 The Go Authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style
 | 
						|
// license that can be found in the LICENSE file.
 | 
						|
 | 
						|
package span
 | 
						|
 | 
						|
import (
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"unicode/utf8"
 | 
						|
)
 | 
						|
 | 
						|
// Parse returns the location represented by the input.
 | 
						|
// All inputs are valid locations, as they can always be a pure filename.
 | 
						|
// The returned span will be normalized, and thus if printed may produce a
 | 
						|
// different string.
 | 
						|
func Parse(input string) Span {
 | 
						|
	// :0:0#0-0:0#0
 | 
						|
	valid := input
 | 
						|
	var hold, offset int
 | 
						|
	hadCol := false
 | 
						|
	suf := rstripSuffix(input)
 | 
						|
	if suf.sep == "#" {
 | 
						|
		offset = suf.num
 | 
						|
		suf = rstripSuffix(suf.remains)
 | 
						|
	}
 | 
						|
	if suf.sep == ":" {
 | 
						|
		valid = suf.remains
 | 
						|
		hold = suf.num
 | 
						|
		hadCol = true
 | 
						|
		suf = rstripSuffix(suf.remains)
 | 
						|
	}
 | 
						|
	switch {
 | 
						|
	case suf.sep == ":":
 | 
						|
		return New(NewURI(suf.remains), NewPoint(suf.num, hold, offset), Point{})
 | 
						|
	case suf.sep == "-":
 | 
						|
		// we have a span, fall out of the case to continue
 | 
						|
	default:
 | 
						|
		// separator not valid, rewind to either the : or the start
 | 
						|
		return New(NewURI(valid), NewPoint(hold, 0, offset), Point{})
 | 
						|
	}
 | 
						|
	// only the span form can get here
 | 
						|
	// at this point we still don't know what the numbers we have mean
 | 
						|
	// if have not yet seen a : then we might have either a line or a column depending
 | 
						|
	// on whether start has a column or not
 | 
						|
	// we build an end point and will fix it later if needed
 | 
						|
	end := NewPoint(suf.num, hold, offset)
 | 
						|
	hold, offset = 0, 0
 | 
						|
	suf = rstripSuffix(suf.remains)
 | 
						|
	if suf.sep == "#" {
 | 
						|
		offset = suf.num
 | 
						|
		suf = rstripSuffix(suf.remains)
 | 
						|
	}
 | 
						|
	if suf.sep != ":" {
 | 
						|
		// turns out we don't have a span after all, rewind
 | 
						|
		return New(NewURI(valid), end, Point{})
 | 
						|
	}
 | 
						|
	valid = suf.remains
 | 
						|
	hold = suf.num
 | 
						|
	suf = rstripSuffix(suf.remains)
 | 
						|
	if suf.sep != ":" {
 | 
						|
		// line#offset only
 | 
						|
		return New(NewURI(valid), NewPoint(hold, 0, offset), end)
 | 
						|
	}
 | 
						|
	// we have a column, so if end only had one number, it is also the column
 | 
						|
	if !hadCol {
 | 
						|
		end = NewPoint(suf.num, end.v.Line, end.v.Offset)
 | 
						|
	}
 | 
						|
	return New(NewURI(suf.remains), NewPoint(suf.num, hold, offset), end)
 | 
						|
}
 | 
						|
 | 
						|
type suffix struct {
 | 
						|
	remains string
 | 
						|
	sep     string
 | 
						|
	num     int
 | 
						|
}
 | 
						|
 | 
						|
func rstripSuffix(input string) suffix {
 | 
						|
	if len(input) == 0 {
 | 
						|
		return suffix{"", "", -1}
 | 
						|
	}
 | 
						|
	remains := input
 | 
						|
	num := -1
 | 
						|
	// first see if we have a number at the end
 | 
						|
	last := strings.LastIndexFunc(remains, func(r rune) bool { return r < '0' || r > '9' })
 | 
						|
	if last >= 0 && last < len(remains)-1 {
 | 
						|
		number, err := strconv.ParseInt(remains[last+1:], 10, 64)
 | 
						|
		if err == nil {
 | 
						|
			num = int(number)
 | 
						|
			remains = remains[:last+1]
 | 
						|
		}
 | 
						|
	}
 | 
						|
	// now see if we have a trailing separator
 | 
						|
	r, w := utf8.DecodeLastRuneInString(remains)
 | 
						|
	if r != ':' && r != '#' && r == '#' {
 | 
						|
		return suffix{input, "", -1}
 | 
						|
	}
 | 
						|
	remains = remains[:len(remains)-w]
 | 
						|
	return suffix{remains, string(r), num}
 | 
						|
}
 |