mirror of
https://github.com/zyedidia/micro.git
synced 2025-06-18 14:55:38 -04:00
Merge remote-tracking branch 'zyedidia/master' into pm
This commit is contained in:
commit
8ad2179423
2
Makefile
2
Makefile
@ -17,6 +17,7 @@ build-quick:
|
||||
|
||||
# Same as 'build' but installs to $GOPATH/bin afterward
|
||||
install: build
|
||||
mkdir -p $(GOPATH)/bin
|
||||
mv micro $(GOPATH)/bin
|
||||
|
||||
# Same as 'build-all' but installs to $GOPATH/bin afterward
|
||||
@ -24,6 +25,7 @@ install-all: runtime install
|
||||
|
||||
# Same as 'build-quick' but installs to $GOPATH/bin afterward
|
||||
install-quick: build-quick
|
||||
mkdir -p $(GOPATH)/bin
|
||||
mv micro $(GOPATH)/bin
|
||||
|
||||
# Updates tcell
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/yosuke-furukawa/json5/encoding/json5"
|
||||
"github.com/zyedidia/json5/encoding/json5"
|
||||
"github.com/zyedidia/tcell"
|
||||
)
|
||||
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/layeh/gopher-luar"
|
||||
@ -24,6 +25,7 @@ const (
|
||||
synLinesDown = 75 // How many lines down to look to do syntax highlighting
|
||||
doubleClickThreshold = 400 // How many milliseconds to wait before a second click is not a double click
|
||||
undoThreshold = 500 // If two events are less than n milliseconds apart, undo both of them
|
||||
autosaveTime = 8 // Number of seconds to wait before autosaving
|
||||
)
|
||||
|
||||
var (
|
||||
@ -61,7 +63,8 @@ var (
|
||||
// Channel of jobs running in the background
|
||||
jobs chan JobFunction
|
||||
// Event channel
|
||||
events chan tcell.Event
|
||||
events chan tcell.Event
|
||||
autosave chan bool
|
||||
)
|
||||
|
||||
// LoadInput determines which files should be loaded into buffers
|
||||
@ -330,6 +333,7 @@ func main() {
|
||||
|
||||
jobs = make(chan JobFunction, 100)
|
||||
events = make(chan tcell.Event, 100)
|
||||
autosave = make(chan bool)
|
||||
|
||||
LoadPlugins()
|
||||
|
||||
@ -360,6 +364,15 @@ func main() {
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(autosaveTime * time.Second)
|
||||
if globalSettings["autosave"].(bool) {
|
||||
autosave <- true
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
// Display everything
|
||||
RedrawAll()
|
||||
@ -372,6 +385,8 @@ func main() {
|
||||
// If a new job has finished while running in the background we should execute the callback
|
||||
f.function(f.output, f.args...)
|
||||
continue
|
||||
case <-autosave:
|
||||
CurView().Save(true)
|
||||
case event = <-events:
|
||||
}
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -8,8 +8,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/yosuke-furukawa/json5/encoding/json5"
|
||||
"github.com/zyedidia/glob"
|
||||
"github.com/zyedidia/json5/encoding/json5"
|
||||
)
|
||||
|
||||
type optionValidator func(string, interface{}) error
|
||||
@ -176,6 +176,7 @@ func GetOption(name string) interface{} {
|
||||
func DefaultGlobalSettings() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"autoindent": true,
|
||||
"autosave": false,
|
||||
"colorcolumn": float64(0),
|
||||
"colorscheme": "zenburn",
|
||||
"cursorline": true,
|
||||
@ -199,6 +200,7 @@ func DefaultGlobalSettings() map[string]interface{} {
|
||||
func DefaultLocalSettings() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"autoindent": true,
|
||||
"autosave": false,
|
||||
"colorcolumn": float64(0),
|
||||
"cursorline": true,
|
||||
"filetype": "Unknown",
|
||||
|
@ -56,6 +56,7 @@ func (l *LeafNode) VSplit(buf *Buffer) {
|
||||
s := new(SplitTree)
|
||||
s.kind = VerticalSplit
|
||||
s.parent = l.parent
|
||||
s.tabNum = l.parent.tabNum
|
||||
newView := NewView(buf)
|
||||
newView.TabNum = l.parent.tabNum
|
||||
newView.Num = len(tab.views)
|
||||
@ -81,6 +82,7 @@ func (l *LeafNode) HSplit(buf *Buffer) {
|
||||
} else {
|
||||
s := new(SplitTree)
|
||||
s.kind = HorizontalSplit
|
||||
s.tabNum = l.parent.tabNum
|
||||
s.parent = l.parent
|
||||
newView := NewView(buf)
|
||||
newView.TabNum = l.parent.tabNum
|
||||
|
@ -44,6 +44,7 @@ func NewTabFromView(v *View) *Tab {
|
||||
|
||||
// SetNum sets all this tab's views to have the correct tab number
|
||||
func (t *Tab) SetNum(num int) {
|
||||
t.tree.tabNum = num
|
||||
for _, v := range t.views {
|
||||
v.TabNum = num
|
||||
}
|
||||
|
@ -157,7 +157,19 @@ func GetModTime(path string) (time.Time, bool) {
|
||||
// StringWidth returns the width of a string where tabs count as `tabsize` width
|
||||
func StringWidth(str string, tabsize int) int {
|
||||
sw := runewidth.StringWidth(str)
|
||||
sw += NumOccurrences(str, '\t') * (tabsize - 1)
|
||||
lineIdx := 0
|
||||
for _, ch := range str {
|
||||
switch ch {
|
||||
case '\t':
|
||||
ts := tabsize - (lineIdx % tabsize)
|
||||
sw += ts - 1
|
||||
lineIdx += ts
|
||||
case '\n':
|
||||
lineIdx = 0
|
||||
default:
|
||||
lineIdx++
|
||||
}
|
||||
}
|
||||
return sw
|
||||
}
|
||||
|
||||
@ -165,16 +177,22 @@ func StringWidth(str string, tabsize int) int {
|
||||
// that have a width larger than 1 (this also counts tabs as `tabsize` width)
|
||||
func WidthOfLargeRunes(str string, tabsize int) int {
|
||||
count := 0
|
||||
lineIdx := 0
|
||||
for _, ch := range str {
|
||||
var w int
|
||||
if ch == '\t' {
|
||||
w = tabsize
|
||||
w = tabsize - (lineIdx % tabsize)
|
||||
} else {
|
||||
w = runewidth.RuneWidth(ch)
|
||||
}
|
||||
if w > 1 {
|
||||
count += (w - 1)
|
||||
}
|
||||
if ch == '\n' {
|
||||
lineIdx = 0
|
||||
} else {
|
||||
lineIdx += w
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
@ -116,3 +116,41 @@ func TestJoinAndSplitCommandArgs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringWidth(t *testing.T) {
|
||||
tabsize := 4
|
||||
if w := StringWidth("1\t2", tabsize); w != 5 {
|
||||
t.Error("StringWidth 1 Failed. Got", w)
|
||||
}
|
||||
if w := StringWidth("\t", tabsize); w != 4 {
|
||||
t.Error("StringWidth 2 Failed. Got", w)
|
||||
}
|
||||
if w := StringWidth("1\t", tabsize); w != 4 {
|
||||
t.Error("StringWidth 3 Failed. Got", w)
|
||||
}
|
||||
if w := StringWidth("\t\t", tabsize); w != 8 {
|
||||
t.Error("StringWidth 4 Failed. Got", w)
|
||||
}
|
||||
if w := StringWidth("12\t2\t", tabsize); w != 8 {
|
||||
t.Error("StringWidth 5 Failed. Got", w)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWidthOfLargeRunes(t *testing.T) {
|
||||
tabsize := 4
|
||||
if w := WidthOfLargeRunes("1\t2", tabsize); w != 2 {
|
||||
t.Error("WidthOfLargeRunes 1 Failed. Got", w)
|
||||
}
|
||||
if w := WidthOfLargeRunes("\t", tabsize); w != 3 {
|
||||
t.Error("WidthOfLargeRunes 2 Failed. Got", w)
|
||||
}
|
||||
if w := WidthOfLargeRunes("1\t", tabsize); w != 2 {
|
||||
t.Error("WidthOfLargeRunes 3 Failed. Got", w)
|
||||
}
|
||||
if w := WidthOfLargeRunes("\t\t", tabsize); w != 6 {
|
||||
t.Error("WidthOfLargeRunes 4 Failed. Got", w)
|
||||
}
|
||||
if w := WidthOfLargeRunes("12\t2\t", tabsize); w != 3 {
|
||||
t.Error("WidthOfLargeRunes 5 Failed. Got", w)
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ type View struct {
|
||||
// Specifies whether or not this view holds a help buffer
|
||||
Type ViewType
|
||||
|
||||
// Actual with and height
|
||||
// Actual width and height
|
||||
width int
|
||||
height int
|
||||
|
||||
@ -194,7 +194,13 @@ func (v *View) ScrollDown(n int) {
|
||||
// causing them to lose the unsaved changes
|
||||
func (v *View) CanClose() bool {
|
||||
if v.Type == vtDefault && v.Buf.IsModified {
|
||||
char, canceled := messenger.LetterPrompt("Save changes to "+v.Buf.Name+" before closing? (y,n,esc) ", 'y', 'n')
|
||||
var char rune
|
||||
var canceled bool
|
||||
if v.Buf.Settings["autosave"].(bool) {
|
||||
char = 'y'
|
||||
} else {
|
||||
char, canceled = messenger.LetterPrompt("Save changes to "+v.Buf.Name+" before closing? (y,n,esc) ", 'y', 'n')
|
||||
}
|
||||
if !canceled {
|
||||
if char == 'y' {
|
||||
v.Save(true)
|
||||
@ -709,6 +715,8 @@ func (v *View) DisplayView() {
|
||||
|
||||
// Now we actually draw the line
|
||||
colN := 0
|
||||
strWidth := 0
|
||||
tabSize := int(v.Buf.Settings["tabsize"].(float64))
|
||||
for _, ch := range line {
|
||||
lineStyle := defStyle
|
||||
|
||||
@ -770,8 +778,9 @@ func (v *View) DisplayView() {
|
||||
v.drawCell(screenX-v.leftCol, screenY, indentChar[0], nil, lineIndentStyle)
|
||||
}
|
||||
// Now the tab has to be displayed as a bunch of spaces
|
||||
tabSize := int(v.Buf.Settings["tabsize"].(float64))
|
||||
for i := 0; i < tabSize-1; i++ {
|
||||
visLoc := strWidth
|
||||
remainder := tabSize - (visLoc % tabSize)
|
||||
for i := 0; i < remainder-1; i++ {
|
||||
screenX++
|
||||
if screenX-v.x-v.leftCol >= v.lineNumOffset {
|
||||
v.drawCell(screenX-v.leftCol, screenY, ' ', nil, lineStyle)
|
||||
@ -795,6 +804,7 @@ func (v *View) DisplayView() {
|
||||
charNum = charNum.Move(1, v.Buf)
|
||||
screenX++
|
||||
colN++
|
||||
strWidth += StringWidth(string(ch), tabSize)
|
||||
}
|
||||
// Here we are at a newline
|
||||
|
||||
@ -825,15 +835,13 @@ func (v *View) DisplayView() {
|
||||
}
|
||||
if screenX-v.x-v.leftCol+i >= v.lineNumOffset {
|
||||
colorcolumn := int(v.Buf.Settings["colorcolumn"].(float64))
|
||||
if colorcolumn != 0 && screenX-v.leftCol+i == colorcolumn-1 {
|
||||
if colorcolumn != 0 && screenX-v.lineNumOffset+i == colorcolumn-1 {
|
||||
if style, ok := colorscheme["color-column"]; ok {
|
||||
fg, _, _ := style.Decompose()
|
||||
lineStyle = lineStyle.Background(fg)
|
||||
}
|
||||
v.drawCell(screenX-v.leftCol+i, screenY, ' ', nil, lineStyle)
|
||||
} else {
|
||||
v.drawCell(screenX-v.leftCol+i, screenY, ' ', nil, lineStyle)
|
||||
}
|
||||
v.drawCell(screenX-v.leftCol+i, screenY, ' ', nil, lineStyle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,13 @@ Here are the options that you can set:
|
||||
|
||||
default value: `2`
|
||||
|
||||
* `autosave`: micro will save the buffer every 8 seconds automatically.
|
||||
Micro also will automatically save and quit when you exit without asking.
|
||||
Be careful when using this feature, because you might accidentally save a file,
|
||||
overwriting what was there before.
|
||||
|
||||
default value: `off`
|
||||
|
||||
---
|
||||
|
||||
Default plugin options:
|
||||
|
Loading…
Reference in New Issue
Block a user