// This stores all the text in the buffer as an array of lines
*LineArray
- Cursor Cursor
+ Cursor Cursor
+ cursors []*Cursor // for multiple cursors
+ curCursor int // the current cursor
// Path to the file on disk
Path string
}
func NewBufferFromString(text, path string) *Buffer {
- return NewBuffer(strings.NewReader(text), path)
+ return NewBuffer(strings.NewReader(text), int64(len(text)), path)
}
// NewBuffer creates a new buffer from a given reader with a given path
-func NewBuffer(reader io.Reader, path string) *Buffer {
+func NewBuffer(reader io.Reader, size int64, path string) *Buffer {
if path != "" {
for _, tab := range tabs {
for _, view := range tab.views {
}
b := new(Buffer)
- b.LineArray = NewLineArray(reader)
+ b.LineArray = NewLineArray(size, reader)
b.Settings = DefaultLocalSettings()
for k, v := range globalSettings {
file.Close()
}
+ b.cursors = []*Cursor{&b.Cursor}
+
return b
}
// UpdateRules updates the syntax rules and filetype for this buffer
// This is called when the colorscheme changes
func (b *Buffer) UpdateRules() {
- b.syntaxDef = highlight.DetectFiletype(syntaxDefs, b.Path, []byte(b.Line(0)))
- if b.highlighter == nil || b.Settings["filetype"].(string) != b.syntaxDef.FileType {
- b.Settings["filetype"] = b.syntaxDef.FileType
- b.highlighter = highlight.NewHighlighter(b.syntaxDef)
- if b.Settings["syntax"].(bool) {
- b.highlighter.HighlightStates(b)
+ rehighlight := false
+ var files []*highlight.File
+ for _, f := range ListRuntimeFiles(RTSyntax) {
+ data, err := f.Data()
+ if err != nil {
+ TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
+ } else {
+ file, err := highlight.ParseFile(data)
+ if err != nil {
+ TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
+ continue
+ }
+ ftdetect, err := highlight.ParseFtDetect(file)
+ if err != nil {
+ TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
+ continue
+ }
+
+ ft := b.Settings["filetype"].(string)
+ if (ft == "Unknown" || ft == "") && !rehighlight {
+ if highlight.MatchFiletype(ftdetect, b.Path, b.lines[0].data) {
+ header := new(highlight.Header)
+ header.FileType = file.FileType
+ header.FtDetect = ftdetect
+ b.syntaxDef, err = highlight.ParseDef(file, header)
+ if err != nil {
+ TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
+ continue
+ }
+ rehighlight = true
+ }
+ } else {
+ if file.FileType == ft && !rehighlight {
+ header := new(highlight.Header)
+ header.FileType = file.FileType
+ header.FtDetect = ftdetect
+ b.syntaxDef, err = highlight.ParseDef(file, header)
+ if err != nil {
+ TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
+ continue
+ }
+ rehighlight = true
+ }
+ }
+ files = append(files, file)
+ }
+ }
+
+ if b.syntaxDef != nil {
+ highlight.ResolveIncludes(b.syntaxDef, files)
+ }
+ files = nil
+
+ if b.highlighter == nil || rehighlight {
+ if b.syntaxDef != nil {
+ b.Settings["filetype"] = b.syntaxDef.FileType
+ b.highlighter = highlight.NewHighlighter(b.syntaxDef)
+ if b.Settings["syntax"].(bool) {
+ b.highlighter.HighlightStates(b)
+ }
}
}
}
b.NumLines = len(b.lines)
}
+func (b *Buffer) MergeCursors() {
+ var cursors []*Cursor
+ for i := 0; i < len(b.cursors); i++ {
+ c1 := b.cursors[i]
+ if c1 != nil {
+ for j := 0; j < len(b.cursors); j++ {
+ c2 := b.cursors[j]
+ if c2 != nil && i != j && c1.Loc == c2.Loc {
+ b.cursors[j] = nil
+ }
+ }
+ cursors = append(cursors, c1)
+ }
+ }
+
+ b.cursors = cursors
+}
+
+func (b *Buffer) UpdateCursors() {
+ for i, c := range b.cursors {
+ c.Num = i
+ }
+}
+
// Save saves the buffer to its default path
func (b *Buffer) Save() error {
return b.SaveAs(b.Path)
func (b *Buffer) SaveAs(filename string) error {
b.UpdateRules()
dir, _ := homedir.Dir()
- b.Path = strings.Replace(filename, "~", dir, 1)
if b.Settings["rmtrailingws"].(bool) {
r, _ := regexp.Compile(`[ \t]+$`)
for lineNum, line := range b.Lines(0, b.NumLines) {
data := []byte(str)
err := ioutil.WriteFile(filename, data, 0644)
if err == nil {
+ b.Path = strings.Replace(filename, "~", dir, 1)
b.IsModified = false
b.ModTime, _ = GetModTime(filename)
return b.Serialize()
b.UpdateRules()
b.Path = filename
- // The user may have already used sudo in which case we won't need the password
- // It's a bit nicer for them if they don't have to enter the password every time
- _, err := RunShellCommand("sudo -v")
- needPassword := err != nil
-
- // If we need the password, we have to close the screen and ask using the shell
- if needPassword {
- // Shut down the screen because we're going to interact directly with the shell
- screen.Fini()
- screen = nil
- }
+ // Shut down the screen because we're going to interact directly with the shell
+ screen.Fini()
+ screen = nil
// Set up everything for the command
cmd := exec.Command("sudo", "tee", filename)
// Start the command
cmd.Start()
- err = cmd.Wait()
+ err := cmd.Wait()
- // If we needed the password, we closed the screen, so we have to initialize it again
- if needPassword {
- // Start the screen back up
- InitScreen()
- }
+ // Start the screen back up
+ InitScreen()
if err == nil {
b.IsModified = false
b.ModTime, _ = GetModTime(filename)