Open at line syntax with filename:line:col

Ref #1010
Ref #887
Ref #836
This commit is contained in:
Zachary Yedidia 2018-02-02 13:57:02 -05:00
parent 35a9245c5d
commit 4790c39dfc
7 changed files with 91 additions and 97 deletions

View file

@ -74,6 +74,33 @@ type SerializedBuffer struct {
ModTime time.Time
}
// NewBufferFromFile opens a new buffer using the given filepath
// It will also automatically handle `~`, and line/column with filename:l:c
// It will return an empty buffer if the filepath does not exist
// and an error if the file is a directory
func NewBufferFromFile(path string) (*Buffer, error) {
filename := GetPath(path)
filename = ReplaceHome(filename)
file, err := os.Open(filename)
fileInfo, _ := os.Stat(filename)
if err == nil && fileInfo.IsDir() {
return nil, errors.New(filename + " is a directory")
}
defer file.Close()
var buf *Buffer
if err != nil {
// File does not exist -- create an empty buffer with that name
buf = NewBufferFromString("", path)
} else {
buf = NewBuffer(file, FSize(file), path)
}
return buf, nil
}
// NewBufferFromString creates a new buffer containing the given
// string
func NewBufferFromString(text, path string) *Buffer {
@ -82,6 +109,26 @@ func NewBufferFromString(text, path string) *Buffer {
// NewBuffer creates a new buffer from a given reader with a given path
func NewBuffer(reader io.Reader, size int64, path string) *Buffer {
startpos := Loc{0, 0}
startposErr := true
if strings.Contains(path, ":") {
var err error
split := strings.Split(path, ":")
path = split[0]
startpos.Y, err = strconv.Atoi(split[1])
if err != nil {
messenger.Error("Error opening file: ", err)
} else {
startposErr = false
if len(split) > 2 {
startpos.X, err = strconv.Atoi(split[2])
if err != nil {
messenger.Error("Error opening file: ", err)
}
}
}
}
if path != "" {
for _, tab := range tabs {
for _, view := range tab.views {
@ -129,11 +176,18 @@ func NewBuffer(reader io.Reader, size int64, path string) *Buffer {
cursorStartX := 0
cursorStartY := 0
// If -startpos LINE,COL was passed, use start position LINE,COL
if len(*flagStartPos) > 0 {
if len(*flagStartPos) > 0 || !startposErr {
positions := strings.Split(*flagStartPos, ",")
if len(positions) == 2 {
lineNum, errPos1 := strconv.Atoi(positions[0])
colNum, errPos2 := strconv.Atoi(positions[1])
if len(positions) == 2 || !startposErr {
var lineNum, colNum int
var errPos1, errPos2 error
if !startposErr {
lineNum = startpos.Y
colNum = startpos.X
} else {
lineNum, errPos1 = strconv.Atoi(positions[0])
colNum, errPos2 = strconv.Atoi(positions[1])
}
if errPos1 == nil && errPos2 == nil {
cursorStartX = colNum
cursorStartY = lineNum - 1
@ -162,7 +216,7 @@ func NewBuffer(reader io.Reader, size int64, path string) *Buffer {
InitLocalSettings(b)
if len(*flagStartPos) == 0 && (b.Settings["savecursor"].(bool) || b.Settings["saveundo"].(bool)) {
if startposErr && len(*flagStartPos) == 0 && (b.Settings["savecursor"].(bool) || b.Settings["saveundo"].(bool)) {
// If either savecursor or saveundo is turned on, we need to load the serialized information
// from ~/.config/micro/buffers
file, err := os.Open(configDir + "/buffers/" + EscapePath(b.AbsPath))

View file

@ -390,24 +390,10 @@ func VSplit(args []string) {
if len(args) == 0 {
CurView().VSplit(NewBufferFromString("", ""))
} else {
filename := args[0]
filename = ReplaceHome(filename)
file, err := os.Open(filename)
fileInfo, _ := os.Stat(filename)
if err == nil && fileInfo.IsDir() {
messenger.Error(filename, " is a directory")
return
}
defer file.Close()
var buf *Buffer
buf, err := NewBufferFromFile(args[0])
if err != nil {
// File does not exist -- create an empty buffer with that name
buf = NewBufferFromString("", filename)
} else {
buf = NewBuffer(file, FSize(file), filename)
messenger.Error(err)
return
}
CurView().VSplit(buf)
}
@ -419,24 +405,10 @@ func HSplit(args []string) {
if len(args) == 0 {
CurView().HSplit(NewBufferFromString("", ""))
} else {
filename := args[0]
filename = ReplaceHome(filename)
file, err := os.Open(filename)
fileInfo, _ := os.Stat(filename)
if err == nil && fileInfo.IsDir() {
messenger.Error(filename, " is a directory")
return
}
defer file.Close()
var buf *Buffer
buf, err := NewBufferFromFile(args[0])
if err != nil {
// File does not exist -- create an empty buffer with that name
buf = NewBufferFromString("", filename)
} else {
buf = NewBuffer(file, FSize(file), filename)
messenger.Error(err)
return
}
CurView().HSplit(buf)
}
@ -459,23 +431,10 @@ func NewTab(args []string) {
if len(args) == 0 {
CurView().AddTab(true)
} else {
filename := args[0]
filename = ReplaceHome(filename)
file, err := os.Open(filename)
fileInfo, _ := os.Stat(filename)
if err == nil && fileInfo.IsDir() {
messenger.Error(filename, " is a directory")
return
}
defer file.Close()
var buf *Buffer
buf, err := NewBufferFromFile(args[0])
if err != nil {
buf = NewBufferFromString("", filename)
} else {
buf = NewBuffer(file, FSize(file), filename)
messenger.Error(err)
return
}
tab := NewTabFromView(NewView(buf))

View file

@ -95,30 +95,13 @@ func LoadInput() []*Buffer {
// Option 1
// We go through each file and load it
for i := 0; i < len(args); i++ {
filename = args[i]
// Check that the file exists
var input *os.File
if _, e := os.Stat(filename); e == nil {
// If it exists we load it into a buffer
input, err = os.Open(filename)
stat, _ := input.Stat()
defer input.Close()
if err != nil {
TermMessage(err)
continue
}
if stat.IsDir() {
TermMessage("Cannot read", filename, "because it is a directory")
continue
}
buf, err := NewBufferFromFile(args[i])
if err != nil {
TermMessage(err)
continue
}
// If the file didn't exist, input will be empty, and we'll open an empty buffer
if input != nil {
buffers = append(buffers, NewBuffer(input, FSize(input), filename))
} else {
buffers = append(buffers, NewBufferFromString("", filename))
}
buffers = append(buffers, buf)
}
} else if !isatty.IsTerminal(os.Stdin.Fd()) {
// Option 2
@ -423,6 +406,7 @@ func main() {
L.SetGlobal("GetLeadingWhitespace", luar.New(L, GetLeadingWhitespace))
L.SetGlobal("MakeCompletion", luar.New(L, MakeCompletion))
L.SetGlobal("NewBuffer", luar.New(L, NewBufferFromString))
L.SetGlobal("NewBufferFromFile", luar.New(L, NewBufferFromFile))
L.SetGlobal("RuneStr", luar.New(L, func(r rune) string {
return string(r)
}))

File diff suppressed because one or more lines are too long

View file

@ -337,3 +337,12 @@ func ReplaceHome(path string) string {
}
return strings.Replace(path, "~", home, 1)
}
// GetPath returns a filename without everything following a `:`
// This is used for opening files like util.go:10:5 to specify a line and column
func GetPath(path string) string {
if strings.Contains(path, ":") {
path = strings.Split(path, ":")[0]
}
return path
}

View file

@ -2,7 +2,6 @@ package main
import (
"fmt"
"os"
"reflect"
"strconv"
"strings"
@ -283,25 +282,11 @@ func (v *View) OpenBuffer(buf *Buffer) {
}
// Open opens the given file in the view
func (v *View) Open(filename string) {
filename = ReplaceHome(filename)
file, err := os.Open(filename)
fileInfo, _ := os.Stat(filename)
if err == nil && fileInfo.IsDir() {
messenger.Error(filename, " is a directory")
return
}
defer file.Close()
var buf *Buffer
func (v *View) Open(path string) {
buf, err := NewBufferFromFile(path)
if err != nil {
messenger.Message(err.Error())
// File does not exist -- create an empty buffer with that name
buf = NewBufferFromString("", filename)
} else {
buf = NewBuffer(file, FSize(file), filename)
messenger.Error(err)
return
}
v.OpenBuffer(buf)
}

View file

@ -65,6 +65,9 @@ functions are given using Go's type system):
* `NewBuffer(text, path string) *Buffer`: creates a new buffer from a given
reader with a given path
* `NewBufferFromFile(path string) *Buffer`: creates a new buffer from a given
path
* `GetLeadingWhitespace() bool`: returns the leading whitespace of the given
string