diff --git a/cmd/micro/action/command.go b/cmd/micro/action/command.go index 3e755951..7a34c6de 100644 --- a/cmd/micro/action/command.go +++ b/cmd/micro/action/command.go @@ -48,6 +48,7 @@ func InitCommands() { "togglelog": Command{(*BufPane).ToggleLogCmd, nil}, "plugin": Command{(*BufPane).PluginCmd, nil}, "reload": Command{(*BufPane).ReloadCmd, nil}, + "reopen": Command{(*BufPane).ReopenCmd, nil}, "cd": Command{(*BufPane).CdCmd, buffer.FileComplete}, "pwd": Command{(*BufPane).PwdCmd, nil}, "open": Command{(*BufPane).OpenCmd, buffer.FileComplete}, @@ -234,6 +235,22 @@ func (h *BufPane) ToggleLogCmd(args []string) { func (h *BufPane) ReloadCmd(args []string) { } +// ReopenCmd reopens the buffer (reload from disk) +func (h *BufPane) ReopenCmd(args []string) { + if h.Buf.Modified() { + InfoBar.YNPrompt("Save file before reopen?", func(yes, canceled bool) { + if !canceled && yes { + h.Save() + h.Buf.ReOpen() + } else if !canceled { + h.Buf.ReOpen() + } + }) + } else { + h.Buf.ReOpen() + } +} + func (h *BufPane) openHelp(page string) error { if data, err := config.FindRuntimeFile(config.RTHelp, page).Data(); err != nil { return errors.New(fmt.Sprint("Unable to load help text", page, "\n", err)) diff --git a/cmd/micro/action/infopane.go b/cmd/micro/action/infopane.go index c42bed30..c83f77d2 100644 --- a/cmd/micro/action/infopane.go +++ b/cmd/micro/action/infopane.go @@ -2,7 +2,6 @@ package action import ( "bytes" - "log" "github.com/zyedidia/micro/cmd/micro/display" "github.com/zyedidia/micro/cmd/micro/info" @@ -184,7 +183,6 @@ func (h *InfoPane) InsertTab() { } } } - log.Println(ins, suggestions) if len(suggestions) == 1 { b.Insert(c.Loc, ins) diff --git a/cmd/micro/buffer/buffer.go b/cmd/micro/buffer/buffer.go index 3c8672dc..b6e7e253 100644 --- a/cmd/micro/buffer/buffer.go +++ b/cmd/micro/buffer/buffer.go @@ -12,13 +12,24 @@ import ( "time" "unicode/utf8" + "github.com/saintfish/chardet" "github.com/zyedidia/micro/cmd/micro/config" "github.com/zyedidia/micro/cmd/micro/highlight" "github.com/zyedidia/micro/cmd/micro/screen" . "github.com/zyedidia/micro/cmd/micro/util" + "golang.org/x/text/encoding/htmlindex" + "golang.org/x/text/encoding/unicode" + "golang.org/x/text/transform" ) -var OpenBuffers []*Buffer +var ( + OpenBuffers []*Buffer + detector *chardet.Detector // encoding detector +) + +func init() { + detector = chardet.NewTextDetector() +} // The BufType defines what kind of buffer this is type BufType struct { @@ -89,6 +100,8 @@ type Buffer struct { // Settings customized by the user Settings map[string]interface{} + Suggestions []string + Messages []*Message } @@ -132,7 +145,7 @@ func NewBufferFromString(text, path string, btype BufType) *Buffer { // NewBuffer creates a new buffer from a given reader with a given path // Ensure that ReadSettings and InitGlobalSettings have been called before creating // a new buffer -func NewBuffer(reader io.Reader, size int64, path string, cursorPosition []string, btype BufType) *Buffer { +func NewBuffer(r io.Reader, size int64, path string, cursorPosition []string, btype BufType) *Buffer { absPath, _ := filepath.Abs(path) b := new(Buffer) @@ -145,6 +158,14 @@ func NewBuffer(reader io.Reader, size int64, path string, cursorPosition []strin } config.InitLocalSettings(b.Settings, b.Path) + enc, err := htmlindex.Get(b.Settings["encoding"].(string)) + if err != nil { + enc = unicode.UTF8 + b.Settings["encoding"] = "utf-8" + } + + reader := transform.NewReader(r, enc.NewDecoder()) + found := false if len(path) > 0 { for _, buf := range OpenBuffers { @@ -263,7 +284,18 @@ func (b *Buffer) FileType() string { // ReOpen reloads the current buffer from disk func (b *Buffer) ReOpen() error { - data, err := ioutil.ReadFile(b.Path) + file, err := os.Open(b.Path) + if err != nil { + return err + } + + enc, err := htmlindex.Get(b.Settings["encoding"].(string)) + if err != nil { + return err + } + + reader := transform.NewReader(file, enc.NewDecoder()) + data, err := ioutil.ReadAll(reader) txt := string(data) if err != nil { diff --git a/cmd/micro/buffer/save.go b/cmd/micro/buffer/save.go index 1d62818e..7337baad 100644 --- a/cmd/micro/buffer/save.go +++ b/cmd/micro/buffer/save.go @@ -1,7 +1,6 @@ package buffer import ( - "bufio" "bytes" "errors" "io" @@ -12,6 +11,9 @@ import ( "github.com/zyedidia/micro/cmd/micro/config" . "github.com/zyedidia/micro/cmd/micro/util" + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/htmlindex" + "golang.org/x/text/transform" ) // LargeFileThreshold is the number of bytes when fastdirty is forced @@ -21,7 +23,7 @@ const LargeFileThreshold = 50000 // overwriteFile opens the given file for writing, truncating if one exists, and then calls // the supplied function with the file as io.Writer object, also making sure the file is // closed afterwards. -func overwriteFile(name string, fn func(io.Writer) error) (err error) { +func overwriteFile(name string, enc encoding.Encoding, fn func(io.Writer) error) (err error) { var file *os.File if file, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil { @@ -34,13 +36,14 @@ func overwriteFile(name string, fn func(io.Writer) error) (err error) { } }() - w := bufio.NewWriter(file) + w := transform.NewWriter(file, enc.NewEncoder()) + // w := bufio.NewWriter(file) if err = fn(w); err != nil { return } - err = w.Flush() + // err = w.Flush() return } @@ -105,7 +108,12 @@ func (b *Buffer) SaveAs(filename string) error { var fileSize int - err := overwriteFile(absFilename, func(file io.Writer) (e error) { + enc, err := htmlindex.Get(b.Settings["encoding"].(string)) + if err != nil { + return err + } + + err = overwriteFile(absFilename, enc, func(file io.Writer) (e error) { if len(b.lines) == 0 { return } diff --git a/cmd/micro/buffer/serialize.go b/cmd/micro/buffer/serialize.go index ccafd1a6..821f0c7a 100644 --- a/cmd/micro/buffer/serialize.go +++ b/cmd/micro/buffer/serialize.go @@ -9,6 +9,7 @@ import ( "github.com/zyedidia/micro/cmd/micro/config" . "github.com/zyedidia/micro/cmd/micro/util" + "golang.org/x/text/encoding/unicode" ) // The SerializedBuffer holds the types that get serialized when a buffer is saved @@ -32,7 +33,7 @@ func (b *Buffer) Serialize() error { name := config.ConfigDir + "/buffers/" + EscapePath(b.AbsPath) - return overwriteFile(name, func(file io.Writer) error { + return overwriteFile(name, unicode.UTF8, func(file io.Writer) error { err := gob.NewEncoder(file).Encode(SerializedBuffer{ b.EventHandler, b.GetActiveCursor().Loc, diff --git a/cmd/micro/buffer/settings.go b/cmd/micro/buffer/settings.go index d7144ca9..fb66d5d9 100644 --- a/cmd/micro/buffer/settings.go +++ b/cmd/micro/buffer/settings.go @@ -43,6 +43,8 @@ func (b *Buffer) SetOption(option, value string) error { } else { b.UpdateRules() } + } else if option == "encoding" { + b.isModified = true } return nil diff --git a/cmd/micro/config/settings.go b/cmd/micro/config/settings.go index 01126d17..8bf7f3fe 100644 --- a/cmd/micro/config/settings.go +++ b/cmd/micro/config/settings.go @@ -12,6 +12,7 @@ import ( "github.com/flynn/json5" "github.com/zyedidia/glob" "github.com/zyedidia/micro/cmd/micro/util" + "golang.org/x/text/encoding/htmlindex" ) type optionValidator func(string, interface{}) error @@ -35,6 +36,7 @@ var optionValidators = map[string]optionValidator{ "colorscheme": validateColorscheme, "colorcolumn": validateNonNegativeValue, "fileformat": validateLineEnding, + "encoding": validateEncoding, } func ReadSettings() error { @@ -134,6 +136,7 @@ func DefaultCommonSettings() map[string]interface{} { "basename": false, "colorcolumn": float64(0), "cursorline": true, + "encoding": "utf-8", "eofnewline": false, "fastdirty": true, "fileformat": "unix", @@ -291,3 +294,8 @@ func validateLineEnding(option string, value interface{}) error { return nil } + +func validateEncoding(option string, value interface{}) error { + _, err := htmlindex.Get(value.(string)) + return err +} diff --git a/cmd/micro/display/bufwindow.go b/cmd/micro/display/bufwindow.go index 9e4e7659..003e6e7a 100644 --- a/cmd/micro/display/bufwindow.go +++ b/cmd/micro/display/bufwindow.go @@ -1,7 +1,6 @@ package display import ( - "log" "strconv" "unicode/utf8" @@ -454,9 +453,7 @@ func (w *BufWindow) displayBuffer() { } if s, ok := config.Colorscheme["color-column"]; ok { - log.Println(vloc.X - w.gutterOffset) if colorcolumn != 0 && vloc.X-w.gutterOffset == colorcolumn { - log.Println("display colorcolumn") fg, _, _ := s.Decompose() style = style.Background(fg) } diff --git a/cmd/micro/display/infowindow.go b/cmd/micro/display/infowindow.go index 111bfcd0..4474781d 100644 --- a/cmd/micro/display/infowindow.go +++ b/cmd/micro/display/infowindow.go @@ -1,7 +1,6 @@ package display import ( - "log" "unicode/utf8" runewidth "github.com/mattn/go-runewidth" @@ -152,10 +151,8 @@ var keydisplay = []string{"^Q Quit, ^S Save, ^O Open, ^G Help, ^E Command Bar, ^ func (i *InfoWindow) displayKeyMenu() { // TODO: maybe make this based on the actual keybindings - log.Println("hi", len(keydisplay), i.Width) for y := 0; y < len(keydisplay); y++ { for x := 0; x < i.Width; x++ { - log.Println(x, i.Y-len(keydisplay)+y) if x < len(keydisplay[y]) { screen.Screen.SetContent(x, i.Y-len(keydisplay)+y, rune(keydisplay[y][x]), nil, config.DefStyle) } else { diff --git a/cmd/micro/display/statusline.go b/cmd/micro/display/statusline.go index e4a26913..f03345f0 100644 --- a/cmd/micro/display/statusline.go +++ b/cmd/micro/display/statusline.go @@ -30,7 +30,7 @@ type StatusLine struct { // NewStatusLine returns a statusline bound to a window func NewStatusLine(win *BufWindow) *StatusLine { s := new(StatusLine) - s.FormatLeft = "$(filename) $(modified)($(line),$(col)) $(opt:filetype) $(opt:fileformat)" + s.FormatLeft = "$(filename) $(modified)($(line),$(col)) $(opt:filetype) $(opt:fileformat) $(opt:encoding)" // s.FormatLeft = "$(filename) $(modified)(line,col) $(opt:filetype) $(opt:fileformat)" s.FormatRight = "$(bind:ToggleKeyMenu): show bindings, $(bind:ToggleHelp): toggle help" s.Info = map[string]func(*buffer.Buffer) string{ diff --git a/cmd/micro/info/infobuffer.go b/cmd/micro/info/infobuffer.go index 3ea3c8b0..d1d299c4 100644 --- a/cmd/micro/info/infobuffer.go +++ b/cmd/micro/info/infobuffer.go @@ -17,7 +17,6 @@ type InfoBuf struct { HasYN bool HasSuggestions bool - Suggestions []string PromptType string