mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-15 21:37:09 +09:00
Add almost full option support
This commit is contained in:
@@ -1009,6 +1009,7 @@ func (h *BufHandler) Escape() bool {
|
|||||||
// Quit this will close the current tab or view that is open
|
// Quit this will close the current tab or view that is open
|
||||||
func (h *BufHandler) Quit() bool {
|
func (h *BufHandler) Quit() bool {
|
||||||
quit := func() {
|
quit := func() {
|
||||||
|
h.Buf.Close()
|
||||||
if len(MainTab().Panes) > 1 {
|
if len(MainTab().Panes) > 1 {
|
||||||
h.Unsplit()
|
h.Unsplit()
|
||||||
} else if len(Tabs.List) > 1 {
|
} else if len(Tabs.List) > 1 {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/zyedidia/micro/cmd/micro/screen"
|
"github.com/zyedidia/micro/cmd/micro/screen"
|
||||||
"github.com/zyedidia/micro/cmd/micro/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Suspend sends micro to the background. This is the same as pressing CtrlZ in most unix programs.
|
// Suspend sends micro to the background. This is the same as pressing CtrlZ in most unix programs.
|
||||||
@@ -19,7 +18,7 @@ func (*BufHandler) Suspend() bool {
|
|||||||
pid := syscall.Getpid()
|
pid := syscall.Getpid()
|
||||||
err := syscall.Kill(pid, syscall.SIGSTOP)
|
err := syscall.Kill(pid, syscall.SIGSTOP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.TermMessage(err)
|
screen.TermMessage(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
screen.TempStart(screenb)
|
screen.TempStart(screenb)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/flynn/json5"
|
"github.com/flynn/json5"
|
||||||
"github.com/zyedidia/micro/cmd/micro/config"
|
"github.com/zyedidia/micro/cmd/micro/config"
|
||||||
"github.com/zyedidia/micro/cmd/micro/util"
|
"github.com/zyedidia/micro/cmd/micro/screen"
|
||||||
"github.com/zyedidia/tcell"
|
"github.com/zyedidia/tcell"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,13 +24,13 @@ func InitBindings() {
|
|||||||
if _, e := os.Stat(filename); e == nil {
|
if _, e := os.Stat(filename); e == nil {
|
||||||
input, err := ioutil.ReadFile(filename)
|
input, err := ioutil.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.TermMessage("Error reading bindings.json file: " + err.Error())
|
screen.TermMessage("Error reading bindings.json file: " + err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json5.Unmarshal(input, &parsed)
|
err = json5.Unmarshal(input, &parsed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.TermMessage("Error reading bindings.json:", err.Error())
|
screen.TermMessage("Error reading bindings.json:", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ func InitBindings() {
|
|||||||
func BindKey(k, v string) {
|
func BindKey(k, v string) {
|
||||||
event, ok := findEvent(k)
|
event, ok := findEvent(k)
|
||||||
if !ok {
|
if !ok {
|
||||||
util.TermMessage(k, "is not a bindable event")
|
screen.TermMessage(k, "is not a bindable event")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/zyedidia/micro/cmd/micro/buffer"
|
"github.com/zyedidia/micro/cmd/micro/buffer"
|
||||||
"github.com/zyedidia/micro/cmd/micro/display"
|
"github.com/zyedidia/micro/cmd/micro/display"
|
||||||
"github.com/zyedidia/micro/cmd/micro/util"
|
"github.com/zyedidia/micro/cmd/micro/screen"
|
||||||
"github.com/zyedidia/tcell"
|
"github.com/zyedidia/tcell"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ func BufMapKey(k Event, action string) {
|
|||||||
BufKeyStrings[k] = action
|
BufKeyStrings[k] = action
|
||||||
BufKeyBindings[k] = f
|
BufKeyBindings[k] = f
|
||||||
} else {
|
} else {
|
||||||
util.TermMessage("Error:", action, "does not exist")
|
screen.TermMessage("Error:", action, "does not exist")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ func BufMapMouse(k MouseEvent, action string) {
|
|||||||
// ensure we don't double bind a key
|
// ensure we don't double bind a key
|
||||||
delete(BufMouseBindings, k)
|
delete(BufMouseBindings, k)
|
||||||
} else {
|
} else {
|
||||||
util.TermMessage("Error:", action, "does not exist")
|
screen.TermMessage("Error:", action, "does not exist")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,6 +268,9 @@ func (h *BufHandler) HSplitBuf(buf *buffer.Buffer) {
|
|||||||
MainTab().Resize()
|
MainTab().Resize()
|
||||||
MainTab().SetActive(len(MainTab().Panes) - 1)
|
MainTab().SetActive(len(MainTab().Panes) - 1)
|
||||||
}
|
}
|
||||||
|
func (h *BufHandler) Close() {
|
||||||
|
h.Buf.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// BufKeyActions contains the list of all possible key actions the bufhandler could execute
|
// BufKeyActions contains the list of all possible key actions the bufhandler could execute
|
||||||
var BufKeyActions = map[string]BufKeyAction{
|
var BufKeyActions = map[string]BufKeyAction{
|
||||||
|
|||||||
@@ -257,12 +257,86 @@ func (h *BufHandler) NewTabCmd(args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetGlobalOption(option, value string) error {
|
||||||
|
if _, ok := config.GlobalSettings[option]; !ok {
|
||||||
|
return config.ErrInvalidOption
|
||||||
|
}
|
||||||
|
|
||||||
|
nativeValue, err := config.GetNativeValue(option, config.GlobalSettings[option], value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
config.GlobalSettings[option] = nativeValue
|
||||||
|
|
||||||
|
if option == "colorscheme" {
|
||||||
|
// LoadSyntaxFiles()
|
||||||
|
config.InitColorscheme()
|
||||||
|
for _, b := range buffer.OpenBuffers {
|
||||||
|
b.UpdateRules()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: info and keymenu option change
|
||||||
|
// if option == "infobar" || option == "keymenu" {
|
||||||
|
// for _, tab := range tabs {
|
||||||
|
// tab.Resize()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
if option == "mouse" {
|
||||||
|
if !nativeValue.(bool) {
|
||||||
|
screen.Screen.DisableMouse()
|
||||||
|
} else {
|
||||||
|
screen.Screen.EnableMouse()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, b := range buffer.OpenBuffers {
|
||||||
|
b.SetOption(option, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
config.WriteSettings(config.ConfigDir + "/settings.json")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetCmd sets an option
|
// SetCmd sets an option
|
||||||
func (h *BufHandler) SetCmd(args []string) {
|
func (h *BufHandler) SetCmd(args []string) {
|
||||||
|
if len(args) < 2 {
|
||||||
|
InfoBar.Error("Not enough arguments")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
option := args[0]
|
||||||
|
value := args[1]
|
||||||
|
|
||||||
|
err := SetGlobalOption(option, value)
|
||||||
|
if err == config.ErrInvalidOption {
|
||||||
|
err := h.Buf.SetOption(option, value)
|
||||||
|
if err != nil {
|
||||||
|
InfoBar.Error(err)
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
InfoBar.Error(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLocalCmd sets an option local to the buffer
|
// SetLocalCmd sets an option local to the buffer
|
||||||
func (h *BufHandler) SetLocalCmd(args []string) {
|
func (h *BufHandler) SetLocalCmd(args []string) {
|
||||||
|
if len(args) < 2 {
|
||||||
|
InfoBar.Error("Not enough arguments")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
option := args[0]
|
||||||
|
value := args[1]
|
||||||
|
|
||||||
|
err := h.Buf.SetOption(option, value)
|
||||||
|
if err != nil {
|
||||||
|
InfoBar.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShowCmd shows the value of the given option
|
// ShowCmd shows the value of the given option
|
||||||
@@ -341,6 +415,8 @@ func (h *BufHandler) TermCmd(args []string) {
|
|||||||
h.AddTab()
|
h.AddTab()
|
||||||
i = 0
|
i = 0
|
||||||
id = MainTab().Panes[0].ID()
|
id = MainTab().Panes[0].ID()
|
||||||
|
} else {
|
||||||
|
MainTab().Panes[i].Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
v := h.GetView()
|
v := h.GetView()
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ type Pane interface {
|
|||||||
display.Window
|
display.Window
|
||||||
ID() uint64
|
ID() uint64
|
||||||
Name() string
|
Name() string
|
||||||
|
Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
type EditPane struct {
|
type EditPane struct {
|
||||||
@@ -31,7 +31,10 @@ func (t *TermHandler) ID() uint64 {
|
|||||||
return t.id
|
return t.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *TermHandler) Close() {}
|
||||||
|
|
||||||
func (t *TermHandler) Quit() {
|
func (t *TermHandler) Quit() {
|
||||||
|
t.Close()
|
||||||
if len(MainTab().Panes) > 1 {
|
if len(MainTab().Panes) > 1 {
|
||||||
t.Unsplit()
|
t.Unsplit()
|
||||||
} else if len(Tabs.List) > 1 {
|
} else if len(Tabs.List) > 1 {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package buffer
|
package buffer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
@@ -14,39 +13,11 @@ import (
|
|||||||
|
|
||||||
"github.com/zyedidia/micro/cmd/micro/config"
|
"github.com/zyedidia/micro/cmd/micro/config"
|
||||||
"github.com/zyedidia/micro/cmd/micro/highlight"
|
"github.com/zyedidia/micro/cmd/micro/highlight"
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/screen"
|
||||||
. "github.com/zyedidia/micro/cmd/micro/util"
|
. "github.com/zyedidia/micro/cmd/micro/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LargeFileThreshold is the number of bytes when fastdirty is forced
|
var OpenBuffers []*Buffer
|
||||||
// because hashing is too slow
|
|
||||||
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) {
|
|
||||||
var file *os.File
|
|
||||||
|
|
||||||
if file, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if e := file.Close(); e != nil && err == nil {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
w := bufio.NewWriter(file)
|
|
||||||
|
|
||||||
if err = fn(w); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = w.Flush()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// The BufType defines what kind of buffer this is
|
// The BufType defines what kind of buffer this is
|
||||||
type BufType struct {
|
type BufType struct {
|
||||||
@@ -63,6 +34,8 @@ var (
|
|||||||
BTScratch = BufType{3, false, true, false}
|
BTScratch = BufType{3, false, true, false}
|
||||||
BTRaw = BufType{4, true, true, false}
|
BTRaw = BufType{4, true, true, false}
|
||||||
BTInfo = BufType{5, false, true, false}
|
BTInfo = BufType{5, false, true, false}
|
||||||
|
|
||||||
|
ErrFileTooLarge = errors.New("File is too large to hash")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Buffer stores the main information about a currently open file including
|
// Buffer stores the main information about a currently open file including
|
||||||
@@ -149,6 +122,8 @@ func NewBufferFromString(text, path string, btype BufType) *Buffer {
|
|||||||
// Ensure that ReadSettings and InitGlobalSettings have been called before creating
|
// Ensure that ReadSettings and InitGlobalSettings have been called before creating
|
||||||
// a new buffer
|
// a new buffer
|
||||||
func NewBuffer(reader io.Reader, size int64, path string, cursorPosition []string, btype BufType) *Buffer {
|
func NewBuffer(reader io.Reader, size int64, path string, cursorPosition []string, btype BufType) *Buffer {
|
||||||
|
absPath, _ := filepath.Abs(path)
|
||||||
|
|
||||||
b := new(Buffer)
|
b := new(Buffer)
|
||||||
b.Type = btype
|
b.Type = btype
|
||||||
|
|
||||||
@@ -162,8 +137,6 @@ func NewBuffer(reader io.Reader, size int64, path string, cursorPosition []strin
|
|||||||
|
|
||||||
b.LineArray = NewLineArray(uint64(size), FFAuto, reader)
|
b.LineArray = NewLineArray(uint64(size), FFAuto, reader)
|
||||||
|
|
||||||
absPath, _ := filepath.Abs(path)
|
|
||||||
|
|
||||||
b.Path = path
|
b.Path = path
|
||||||
b.AbsPath = absPath
|
b.AbsPath = absPath
|
||||||
|
|
||||||
@@ -187,7 +160,7 @@ func NewBuffer(reader io.Reader, size int64, path string, cursorPosition []strin
|
|||||||
if b.Settings["savecursor"].(bool) || b.Settings["saveundo"].(bool) {
|
if b.Settings["savecursor"].(bool) || b.Settings["saveundo"].(bool) {
|
||||||
err := b.Unserialize()
|
err := b.Unserialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
TermMessage(err)
|
screen.TermMessage(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,9 +173,23 @@ func NewBuffer(reader io.Reader, size int64, path string, cursorPosition []strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenBuffers = append(OpenBuffers, b)
|
||||||
|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close removes this buffer from the list of open buffers
|
||||||
|
func (b *Buffer) Close() {
|
||||||
|
for i, buf := range OpenBuffers {
|
||||||
|
if b == buf {
|
||||||
|
copy(OpenBuffers[i:], OpenBuffers[i+1:])
|
||||||
|
OpenBuffers[len(OpenBuffers)-1] = nil
|
||||||
|
OpenBuffers = OpenBuffers[:len(OpenBuffers)-1]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetName returns the name that should be displayed in the statusline
|
// GetName returns the name that should be displayed in the statusline
|
||||||
// for this buffer
|
// for this buffer
|
||||||
func (b *Buffer) GetName() string {
|
func (b *Buffer) GetName() string {
|
||||||
@@ -294,19 +281,37 @@ func (b *Buffer) Modified() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// calcHash calculates md5 hash of all lines in the buffer
|
// calcHash calculates md5 hash of all lines in the buffer
|
||||||
func calcHash(b *Buffer, out *[md5.Size]byte) {
|
func calcHash(b *Buffer, out *[md5.Size]byte) error {
|
||||||
h := md5.New()
|
h := md5.New()
|
||||||
|
|
||||||
|
size := 0
|
||||||
if len(b.lines) > 0 {
|
if len(b.lines) > 0 {
|
||||||
h.Write(b.lines[0].data)
|
n, e := h.Write(b.lines[0].data)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
size += n
|
||||||
|
|
||||||
for _, l := range b.lines[1:] {
|
for _, l := range b.lines[1:] {
|
||||||
h.Write([]byte{'\n'})
|
n, e = h.Write([]byte{'\n'})
|
||||||
h.Write(l.data)
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
size += n
|
||||||
|
n, e = h.Write(l.data)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
size += n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if size > LargeFileThreshold {
|
||||||
|
return ErrFileTooLarge
|
||||||
|
}
|
||||||
|
|
||||||
h.Sum((*out)[:0])
|
h.Sum((*out)[:0])
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Buffer) insert(pos Loc, value []byte) {
|
func (b *Buffer) insert(pos Loc, value []byte) {
|
||||||
@@ -334,16 +339,16 @@ func (b *Buffer) UpdateRules() {
|
|||||||
for _, f := range config.ListRuntimeFiles(config.RTSyntax) {
|
for _, f := range config.ListRuntimeFiles(config.RTSyntax) {
|
||||||
data, err := f.Data()
|
data, err := f.Data()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
|
screen.TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
|
||||||
} else {
|
} else {
|
||||||
file, err := highlight.ParseFile(data)
|
file, err := highlight.ParseFile(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
|
screen.TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ftdetect, err := highlight.ParseFtDetect(file)
|
ftdetect, err := highlight.ParseFtDetect(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
|
screen.TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +360,7 @@ func (b *Buffer) UpdateRules() {
|
|||||||
header.FtDetect = ftdetect
|
header.FtDetect = ftdetect
|
||||||
b.SyntaxDef, err = highlight.ParseDef(file, header)
|
b.SyntaxDef, err = highlight.ParseDef(file, header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
|
screen.TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
rehighlight = true
|
rehighlight = true
|
||||||
@@ -367,7 +372,7 @@ func (b *Buffer) UpdateRules() {
|
|||||||
header.FtDetect = ftdetect
|
header.FtDetect = ftdetect
|
||||||
b.SyntaxDef, err = highlight.ParseDef(file, header)
|
b.SyntaxDef, err = highlight.ParseDef(file, header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
|
screen.TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
rehighlight = true
|
rehighlight = true
|
||||||
@@ -392,6 +397,14 @@ func (b *Buffer) UpdateRules() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearMatches clears all of the syntax highlighting for the buffer
|
||||||
|
func (b *Buffer) ClearMatches() {
|
||||||
|
for i := range b.lines {
|
||||||
|
b.SetMatch(i, nil)
|
||||||
|
b.SetState(i, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// IndentString returns this buffer's indent method (a tabstop or n spaces
|
// IndentString returns this buffer's indent method (a tabstop or n spaces
|
||||||
// depending on the settings)
|
// depending on the settings)
|
||||||
func (b *Buffer) IndentString(tabsize int) string {
|
func (b *Buffer) IndentString(tabsize int) string {
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ func (eh *EventHandler) Execute(t *TextEvent) {
|
|||||||
// for pl := range loadedPlugins {
|
// for pl := range loadedPlugins {
|
||||||
// ret, err := Call(pl+".onBeforeTextEvent", t)
|
// ret, err := Call(pl+".onBeforeTextEvent", t)
|
||||||
// if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") {
|
// if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") {
|
||||||
// util.TermMessage(err)
|
// screen.TermMessage(err)
|
||||||
// }
|
// }
|
||||||
// if val, ok := ret.(lua.LBool); ok && val == lua.LFalse {
|
// if val, ok := ret.(lua.LBool); ok && val == lua.LFalse {
|
||||||
// return
|
// return
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package buffer
|
package buffer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
@@ -8,11 +9,40 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
. "github.com/zyedidia/micro/cmd/micro/util"
|
|
||||||
|
|
||||||
"github.com/zyedidia/micro/cmd/micro/config"
|
"github.com/zyedidia/micro/cmd/micro/config"
|
||||||
|
. "github.com/zyedidia/micro/cmd/micro/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// LargeFileThreshold is the number of bytes when fastdirty is forced
|
||||||
|
// because hashing is too slow
|
||||||
|
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) {
|
||||||
|
var file *os.File
|
||||||
|
|
||||||
|
if file, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if e := file.Close(); e != nil && err == nil {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
w := bufio.NewWriter(file)
|
||||||
|
|
||||||
|
if err = fn(w); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = w.Flush()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Save saves the buffer to its default path
|
// Save saves the buffer to its default path
|
||||||
func (b *Buffer) Save() error {
|
func (b *Buffer) Save() error {
|
||||||
return b.SaveAs(b.Path)
|
return b.SaveAs(b.Path)
|
||||||
|
|||||||
43
cmd/micro/buffer/settings.go
Normal file
43
cmd/micro/buffer/settings.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package buffer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/config"
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/screen"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetOption sets a given option to a value just for this buffer
|
||||||
|
func (b *Buffer) SetOption(option, value string) error {
|
||||||
|
if _, ok := b.Settings[option]; !ok {
|
||||||
|
return config.ErrInvalidOption
|
||||||
|
}
|
||||||
|
|
||||||
|
nativeValue, err := config.GetNativeValue(option, b.Settings[option], value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Settings[option] = nativeValue
|
||||||
|
|
||||||
|
if option == "fastdirty" {
|
||||||
|
if !nativeValue.(bool) {
|
||||||
|
e := calcHash(b, &b.origHash)
|
||||||
|
if e == ErrFileTooLarge {
|
||||||
|
b.Settings["fastdirty"] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if option == "statusline" {
|
||||||
|
screen.Redraw()
|
||||||
|
} else if option == "filetype" {
|
||||||
|
b.UpdateRules()
|
||||||
|
} else if option == "fileformat" {
|
||||||
|
b.isModified = true
|
||||||
|
} else if option == "syntax" {
|
||||||
|
if !nativeValue.(bool) {
|
||||||
|
b.ClearMatches()
|
||||||
|
} else {
|
||||||
|
b.UpdateRules()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -6,19 +6,26 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/flynn/json5"
|
"github.com/flynn/json5"
|
||||||
"github.com/zyedidia/glob"
|
"github.com/zyedidia/glob"
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type optionValidator func(string, interface{}) error
|
type optionValidator func(string, interface{}) error
|
||||||
|
|
||||||
// The options that the user can set
|
var (
|
||||||
var GlobalSettings map[string]interface{}
|
ErrInvalidOption = errors.New("Invalid option")
|
||||||
|
ErrInvalidValue = errors.New("Invalid value")
|
||||||
|
|
||||||
// This is the raw parsed json
|
// The options that the user can set
|
||||||
var parsedSettings map[string]interface{}
|
GlobalSettings map[string]interface{}
|
||||||
|
|
||||||
|
// This is the raw parsed json
|
||||||
|
parsedSettings map[string]interface{}
|
||||||
|
)
|
||||||
|
|
||||||
// Options with validators
|
// Options with validators
|
||||||
var optionValidators = map[string]optionValidator{
|
var optionValidators = map[string]optionValidator{
|
||||||
@@ -120,22 +127,6 @@ func GetGlobalOption(name string) interface{} {
|
|||||||
return GlobalSettings[name]
|
return GlobalSettings[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLocalOption returns the local value of the given option
|
|
||||||
// func GetLocalOption(name string, buf *Buffer) interface{} {
|
|
||||||
// return buf.Settings[name]
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO: get option for current buffer
|
|
||||||
// GetOption returns the value of the given option
|
|
||||||
// If there is a local version of the option, it returns that
|
|
||||||
// otherwise it will return the global version
|
|
||||||
// func GetOption(name string) interface{} {
|
|
||||||
// if GetLocalOption(name, CurView().Buf) != nil {
|
|
||||||
// return GetLocalOption(name, CurView().Buf)
|
|
||||||
// }
|
|
||||||
// return GetGlobalOption(name)
|
|
||||||
// }
|
|
||||||
|
|
||||||
func DefaultCommonSettings() map[string]interface{} {
|
func DefaultCommonSettings() map[string]interface{} {
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"autoindent": true,
|
"autoindent": true,
|
||||||
@@ -196,199 +187,35 @@ func DefaultLocalSettings() map[string]interface{} {
|
|||||||
return common
|
return common
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: everything else
|
func GetNativeValue(option string, realValue interface{}, value string) (interface{}, error) {
|
||||||
|
var native interface{}
|
||||||
|
kind := reflect.TypeOf(realValue).Kind()
|
||||||
|
if kind == reflect.Bool {
|
||||||
|
b, err := util.ParseBool(value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrInvalidValue
|
||||||
|
}
|
||||||
|
native = b
|
||||||
|
} else if kind == reflect.String {
|
||||||
|
native = value
|
||||||
|
} else if kind == reflect.Float64 {
|
||||||
|
i, err := strconv.Atoi(value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrInvalidValue
|
||||||
|
}
|
||||||
|
native = float64(i)
|
||||||
|
} else {
|
||||||
|
return nil, ErrInvalidValue
|
||||||
|
}
|
||||||
|
|
||||||
// SetOption attempts to set the given option to the value
|
if err := OptionIsValid(option, native); err != nil {
|
||||||
// By default it will set the option as global, but if the option
|
return nil, err
|
||||||
// is local only it will set the local version
|
}
|
||||||
// Use setlocal to force an option to be set locally
|
return native, nil
|
||||||
// func SetOption(option, value string) error {
|
}
|
||||||
// if _, ok := GlobalSettings[option]; !ok {
|
|
||||||
// if _, ok := CurView().Buf.Settings[option]; !ok {
|
|
||||||
// return errors.New("Invalid option")
|
|
||||||
// }
|
|
||||||
// SetLocalOption(option, value, CurView())
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// var nativeValue interface{}
|
|
||||||
//
|
|
||||||
// kind := reflect.TypeOf(GlobalSettings[option]).Kind()
|
|
||||||
// if kind == reflect.Bool {
|
|
||||||
// b, err := ParseBool(value)
|
|
||||||
// if err != nil {
|
|
||||||
// return errors.New("Invalid value")
|
|
||||||
// }
|
|
||||||
// nativeValue = b
|
|
||||||
// } else if kind == reflect.String {
|
|
||||||
// nativeValue = value
|
|
||||||
// } else if kind == reflect.Float64 {
|
|
||||||
// i, err := strconv.Atoi(value)
|
|
||||||
// if err != nil {
|
|
||||||
// return errors.New("Invalid value")
|
|
||||||
// }
|
|
||||||
// nativeValue = float64(i)
|
|
||||||
// } else {
|
|
||||||
// return errors.New("Option has unsupported value type")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if err := optionIsValid(option, nativeValue); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// GlobalSettings[option] = nativeValue
|
|
||||||
//
|
|
||||||
// if option == "colorscheme" {
|
|
||||||
// // LoadSyntaxFiles()
|
|
||||||
// InitColorscheme()
|
|
||||||
// for _, tab := range tabs {
|
|
||||||
// for _, view := range tab.Views {
|
|
||||||
// view.Buf.UpdateRules()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if option == "infobar" || option == "keymenu" {
|
|
||||||
// for _, tab := range tabs {
|
|
||||||
// tab.Resize()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if option == "mouse" {
|
|
||||||
// if !nativeValue.(bool) {
|
|
||||||
// screen.DisableMouse()
|
|
||||||
// } else {
|
|
||||||
// screen.EnableMouse()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if len(tabs) != 0 {
|
|
||||||
// if _, ok := CurView().Buf.Settings[option]; ok {
|
|
||||||
// for _, tab := range tabs {
|
|
||||||
// for _, view := range tab.Views {
|
|
||||||
// SetLocalOption(option, value, view)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // SetLocalOption sets the local version of this option
|
|
||||||
// func SetLocalOption(option, value string, view *View) error {
|
|
||||||
// buf := view.Buf
|
|
||||||
// if _, ok := buf.Settings[option]; !ok {
|
|
||||||
// return errors.New("Invalid option")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// var nativeValue interface{}
|
|
||||||
//
|
|
||||||
// kind := reflect.TypeOf(buf.Settings[option]).Kind()
|
|
||||||
// if kind == reflect.Bool {
|
|
||||||
// b, err := ParseBool(value)
|
|
||||||
// if err != nil {
|
|
||||||
// return errors.New("Invalid value")
|
|
||||||
// }
|
|
||||||
// nativeValue = b
|
|
||||||
// } else if kind == reflect.String {
|
|
||||||
// nativeValue = value
|
|
||||||
// } else if kind == reflect.Float64 {
|
|
||||||
// i, err := strconv.Atoi(value)
|
|
||||||
// if err != nil {
|
|
||||||
// return errors.New("Invalid value")
|
|
||||||
// }
|
|
||||||
// nativeValue = float64(i)
|
|
||||||
// } else {
|
|
||||||
// return errors.New("Option has unsupported value type")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if err := optionIsValid(option, nativeValue); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if option == "fastdirty" {
|
|
||||||
// // If it is being turned off, we have to hash every open buffer
|
|
||||||
// var empty [md5.Size]byte
|
|
||||||
// var wg sync.WaitGroup
|
|
||||||
//
|
|
||||||
// for _, tab := range tabs {
|
|
||||||
// for _, v := range tab.Views {
|
|
||||||
// if !nativeValue.(bool) {
|
|
||||||
// if v.Buf.origHash == empty {
|
|
||||||
// wg.Add(1)
|
|
||||||
//
|
|
||||||
// go func(b *Buffer) { // calculate md5 hash of the file
|
|
||||||
// defer wg.Done()
|
|
||||||
//
|
|
||||||
// if file, e := os.Open(b.AbsPath); e == nil {
|
|
||||||
// defer file.Close()
|
|
||||||
//
|
|
||||||
// h := md5.New()
|
|
||||||
//
|
|
||||||
// if _, e = io.Copy(h, file); e == nil {
|
|
||||||
// h.Sum(b.origHash[:0])
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }(v.Buf)
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// v.Buf.IsModified = v.Buf.Modified()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// wg.Wait()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// buf.Settings[option] = nativeValue
|
|
||||||
//
|
|
||||||
// if option == "statusline" {
|
|
||||||
// view.ToggleStatusLine()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if option == "filetype" {
|
|
||||||
// // LoadSyntaxFiles()
|
|
||||||
// InitColorscheme()
|
|
||||||
// buf.UpdateRules()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if option == "fileformat" {
|
|
||||||
// buf.IsModified = true
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if option == "syntax" {
|
|
||||||
// if !nativeValue.(bool) {
|
|
||||||
// buf.ClearMatches()
|
|
||||||
// } else {
|
|
||||||
// if buf.highlighter != nil {
|
|
||||||
// buf.highlighter.HighlightStates(buf)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // SetOptionAndSettings sets the given option and saves the option setting to the settings config file
|
|
||||||
// func SetOptionAndSettings(option, value string) {
|
|
||||||
// filename := ConfigDir + "/settings.json"
|
|
||||||
//
|
|
||||||
// err := SetOption(option, value)
|
|
||||||
//
|
|
||||||
// if err != nil {
|
|
||||||
// messenger.Error(err.Error())
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// err = WriteSettings(filename)
|
|
||||||
// if err != nil {
|
|
||||||
// messenger.Error("Error writing to settings.json: " + err.Error())
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
func optionIsValid(option string, value interface{}) error {
|
// OptionIsValid checks if a value is valid for a certain option
|
||||||
|
func OptionIsValid(option string, value interface{}) error {
|
||||||
if validator, ok := optionValidators[option]; ok {
|
if validator, ok := optionValidators[option]; ok {
|
||||||
return validator(option, value)
|
return validator(option, value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
"github.com/zyedidia/micro/cmd/micro/buffer"
|
"github.com/zyedidia/micro/cmd/micro/buffer"
|
||||||
"github.com/zyedidia/micro/cmd/micro/config"
|
"github.com/zyedidia/micro/cmd/micro/config"
|
||||||
"github.com/zyedidia/micro/cmd/micro/screen"
|
"github.com/zyedidia/micro/cmd/micro/screen"
|
||||||
"github.com/zyedidia/micro/cmd/micro/util"
|
|
||||||
"github.com/zyedidia/tcell"
|
"github.com/zyedidia/tcell"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -123,7 +122,7 @@ func LoadInput() []*buffer.Buffer {
|
|||||||
|
|
||||||
buf, err := buffer.NewBufferFromFile(args[i], buffer.BTDefault)
|
buf, err := buffer.NewBufferFromFile(args[i], buffer.BTDefault)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.TermMessage(err)
|
screen.TermMessage(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// If the file didn't exist, input will be empty, and we'll open an empty buffer
|
// If the file didn't exist, input will be empty, and we'll open an empty buffer
|
||||||
@@ -135,7 +134,7 @@ func LoadInput() []*buffer.Buffer {
|
|||||||
// and we should read from stdin
|
// and we should read from stdin
|
||||||
input, err = ioutil.ReadAll(os.Stdin)
|
input, err = ioutil.ReadAll(os.Stdin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.TermMessage("Error reading from stdin: ", err)
|
screen.TermMessage("Error reading from stdin: ", err)
|
||||||
input = []byte{}
|
input = []byte{}
|
||||||
}
|
}
|
||||||
buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, buffer.BTDefault))
|
buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, buffer.BTDefault))
|
||||||
@@ -154,12 +153,12 @@ func main() {
|
|||||||
InitFlags()
|
InitFlags()
|
||||||
err = config.InitConfigDir(*flagConfigDir)
|
err = config.InitConfigDir(*flagConfigDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.TermMessage(err)
|
screen.TermMessage(err)
|
||||||
}
|
}
|
||||||
config.InitRuntimeFiles()
|
config.InitRuntimeFiles()
|
||||||
err = config.ReadSettings()
|
err = config.ReadSettings()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.TermMessage(err)
|
screen.TermMessage(err)
|
||||||
}
|
}
|
||||||
config.InitGlobalSettings()
|
config.InitGlobalSettings()
|
||||||
action.InitBindings()
|
action.InitBindings()
|
||||||
@@ -167,7 +166,7 @@ func main() {
|
|||||||
|
|
||||||
err = config.InitColorscheme()
|
err = config.InitColorscheme()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.TermMessage(err)
|
screen.TermMessage(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
screen.Init()
|
screen.Init()
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
package util
|
package screen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/zyedidia/micro/cmd/micro/screen"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TermMessage sends a message to the user in the terminal. This usually occurs before
|
// TermMessage sends a message to the user in the terminal. This usually occurs before
|
||||||
@@ -16,7 +14,7 @@ import (
|
|||||||
// This will write the message, and wait for the user
|
// This will write the message, and wait for the user
|
||||||
// to press and key to continue
|
// to press and key to continue
|
||||||
func TermMessage(msg ...interface{}) {
|
func TermMessage(msg ...interface{}) {
|
||||||
screenb := screen.TempFini()
|
screenb := TempFini()
|
||||||
|
|
||||||
fmt.Println(msg...)
|
fmt.Println(msg...)
|
||||||
fmt.Print("\nPress enter to continue")
|
fmt.Print("\nPress enter to continue")
|
||||||
@@ -24,7 +22,7 @@ func TermMessage(msg ...interface{}) {
|
|||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
reader.ReadString('\n')
|
reader.ReadString('\n')
|
||||||
|
|
||||||
screen.TempStart(screenb)
|
TempStart(screenb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TermError sends an error to the user in the terminal. Like TermMessage except formatted
|
// TermError sends an error to the user in the terminal. Like TermMessage except formatted
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
|
|
||||||
"github.com/zyedidia/micro/cmd/micro/screen"
|
"github.com/zyedidia/micro/cmd/micro/screen"
|
||||||
"github.com/zyedidia/micro/cmd/micro/shellwords"
|
"github.com/zyedidia/micro/cmd/micro/shellwords"
|
||||||
"github.com/zyedidia/micro/cmd/micro/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExecCommand executes a command using exec
|
// ExecCommand executes a command using exec
|
||||||
@@ -108,7 +107,7 @@ func RunInteractiveShell(input string, wait bool, getOutput bool) (string, error
|
|||||||
|
|
||||||
if wait {
|
if wait {
|
||||||
// This is just so we don't return right away and let the user press enter to return
|
// This is just so we don't return right away and let the user press enter to return
|
||||||
util.TermMessage("")
|
screen.TermMessage("")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the screen back up
|
// Start the screen back up
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
@@ -309,6 +310,19 @@ func GetCharPosInLine(b []byte, visualPos int, tabsize int) int {
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseBool is almost exactly like strconv.ParseBool, except it also accepts 'on' and 'off'
|
||||||
|
// as 'true' and 'false' respectively
|
||||||
|
func ParseBool(str string) (bool, error) {
|
||||||
|
if str == "on" {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if str == "off" {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return strconv.ParseBool(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp clamps a value between min and max
|
||||||
func Clamp(val, min, max int) int {
|
func Clamp(val, min, max int) int {
|
||||||
if val < min {
|
if val < min {
|
||||||
val = min
|
val = min
|
||||||
|
|||||||
Reference in New Issue
Block a user