Add support for switching between crlf and lf

Dos and Unix line endings are now both supported (previously on unix
line endings were supported) and can be accessed via the `fileformat`
option. The file format will be automatically detected and displayed in
the statusline but can be overriden.

Possible values for the `fileformat` option are `dos` and `unix`.

Closes #443
Closes #755
This commit is contained in:
Zachary Yedidia
2017-08-24 13:13:14 -04:00
parent 69c6d8a099
commit 9628b73525
5 changed files with 69 additions and 3 deletions

View File

@@ -19,6 +19,13 @@ import (
"github.com/zyedidia/micro/cmd/micro/highlight"
)
var (
// 0 - no line type detected
// 1 - lf detected
// 2 - crlf detected
fileformat = 0
)
// Buffer stores the text for files that are loaded into the text editor
// It uses a rope to efficiently store the string and contains some
// simple functions for saving and wrapper functions for modifying the rope
@@ -88,6 +95,12 @@ func NewBuffer(reader io.Reader, size int64, path string) *Buffer {
}
}
if fileformat == 1 {
b.Settings["fileformat"] = "unix"
} else if fileformat == 2 {
b.Settings["fileformat"] = "dos"
}
absPath, _ := filepath.Abs(path)
b.Path = path
@@ -355,7 +368,7 @@ func (b *Buffer) Serialize() error {
b.ModTime,
})
}
file.Close()
err = file.Close()
return err
}
return nil
@@ -383,7 +396,7 @@ func (b *Buffer) SaveAs(filename string) error {
b.Insert(end, "\n")
}
}
str := b.String()
str := b.SaveString(b.Settings["fileformat"] == "dos")
data := []byte(str)
err := ioutil.WriteFile(filename, data, 0644)
if err == nil {
@@ -408,7 +421,7 @@ func (b *Buffer) SaveAsWithSudo(filename string) error {
// Set up everything for the command
cmd := exec.Command("sudo", "tee", filename)
cmd.Stdin = bytes.NewBufferString(b.String())
cmd.Stdin = bytes.NewBufferString(b.SaveString(b.Settings["fileformat"] == "dos"))
// This is a trap for Ctrl-C so that it doesn't kill micro
// Instead we trap Ctrl-C to kill the program we're running

View File

@@ -71,6 +71,12 @@ func NewLineArray(size int64, reader io.Reader) *LineArray {
n := 0
for {
data, err := br.ReadBytes('\n')
if len(data) > 0 && data[len(data)-2] == '\r' {
data = append(data[:len(data)-2], '\n')
fileformat = 2
} else if len(data) > 0 {
fileformat = 1
}
if n >= 1000 && loaded >= 0 {
totalLinesNum := int(float64(size) * (float64(n) / float64(loaded)))
@@ -114,6 +120,23 @@ func (la *LineArray) String() string {
return str
}
// SaveString returns the string that should be written to disk when
// the line array is saved
// It is the same as string but uses crlf or lf line endings depending
func (la *LineArray) SaveString(useCrlf bool) string {
str := ""
for i, l := range la.lines {
str += string(l.data)
if i != len(la.lines)-1 {
if useCrlf {
str += "\r"
}
str += "\n"
}
}
return str
}
// NewlineBelow adds a newline below the given line number
func (la *LineArray) NewlineBelow(y int) {
la.lines = append(la.lines, Line{[]byte(" "), nil, nil, false})

View File

@@ -27,6 +27,7 @@ var optionValidators = map[string]optionValidator{
"scrollspeed": validateNonNegativeValue,
"colorscheme": validateColorscheme,
"colorcolumn": validateNonNegativeValue,
"fileformat": validateLineEnding,
}
// InitGlobalSettings initializes the options map and sets all options to their default values
@@ -220,6 +221,7 @@ func DefaultGlobalSettings() map[string]interface{} {
},
"pluginrepos": []string{},
"useprimary": true,
"fileformat": "unix",
}
}
@@ -251,6 +253,7 @@ func DefaultLocalSettings() map[string]interface{} {
"tabsize": float64(4),
"tabstospaces": false,
"useprimary": true,
"fileformat": "unix",
}
}
@@ -365,6 +368,10 @@ func SetLocalOption(option, value string, view *View) error {
buf.UpdateRules()
}
if option == "fileformat" {
buf.IsModified = true
}
if option == "syntax" {
if !nativeValue.(bool) {
buf.ClearMatches()
@@ -445,3 +452,17 @@ func validateColorscheme(option string, value interface{}) error {
return nil
}
func validateLineEnding(option string, value interface{}) error {
endingType, ok := value.(string)
if !ok {
return errors.New("Expected string type for file format")
}
if endingType != "unix" && endingType != "dos" {
return errors.New("File format must be either 'unix' or 'dos'")
}
return nil
}

View File

@@ -36,6 +36,8 @@ func (sline *Statusline) Display() {
// Add the filetype
file += " " + sline.view.Buf.FileType()
file += " " + sline.view.Buf.Settings["fileformat"].(string)
rightText := ""
if len(helpBinding) > 0 {
rightText = helpBinding + " for help "

View File

@@ -173,6 +173,13 @@ Default plugin options:
default value: `on`
* `fileformat`: this determines what kind of line endings micro will use for the file. Unix line endings
are just `\n` (lf) whereas dos line endings are `\r\n` (crlf). The two possible values for this option
are `unix` and `dos`. The fileformat will be automatically detected and displayed on the statusline but
this option is useful if you would like to change the line endings or if you are starting a new file.
default value: `unix`
Any option you set in the editor will be saved to the file
~/.config/micro/settings.json so, in effect, your configuration file will be
created for you. If you'd like to take your configuration with you to another