mirror of
https://github.com/zyedidia/micro
synced 2024-11-05 17:41:24 +00:00
Add support for tabs
Merge branch 'tabbar' This branch adds support for having multiple tabs open, each viewing one file. Use CtrlT to open a new tab empty tab and then CtrlO to open a file in that tab. Use can also just open multiple files from the command line: `micro file1.txt file2.txt ...`. Use Ctrl-] and Ctrl-\ to move between the tabs, or simply click them with the mouse.
This commit is contained in:
commit
82c7994e68
11 changed files with 295 additions and 88 deletions
|
@ -73,6 +73,9 @@ var bindingActions = map[string]func(*View) bool{
|
|||
"ShellMode": (*View).ShellMode,
|
||||
"CommandMode": (*View).CommandMode,
|
||||
"Quit": (*View).Quit,
|
||||
"AddTab": (*View).AddTab,
|
||||
"PreviousTab": (*View).PreviousTab,
|
||||
"NextTab": (*View).NextTab,
|
||||
}
|
||||
|
||||
var bindingKeys = map[string]tcell.Key{
|
||||
|
@ -380,6 +383,9 @@ func DefaultBindings() map[string]string {
|
|||
"CtrlD": "DuplicateLine",
|
||||
"CtrlV": "Paste",
|
||||
"CtrlA": "SelectAll",
|
||||
"CtrlT": "AddTab",
|
||||
"CtrlRightSq": "PreviousTab",
|
||||
"CtrlBackslash": "NextTab",
|
||||
"Home": "Start",
|
||||
"End": "End",
|
||||
"PageUp": "CursorPageUp",
|
||||
|
@ -902,7 +908,7 @@ func (v *View) OpenFile() bool {
|
|||
if v.CanClose("Continue? (yes, no, save) ") {
|
||||
filename, canceled := messenger.Prompt("File to open: ", "Open")
|
||||
if canceled {
|
||||
return true
|
||||
return false
|
||||
}
|
||||
home, _ := homedir.Dir()
|
||||
filename = strings.Replace(filename, "~", home, 1)
|
||||
|
@ -910,12 +916,13 @@ func (v *View) OpenFile() bool {
|
|||
|
||||
if err != nil {
|
||||
messenger.Error(err.Error())
|
||||
return true
|
||||
return false
|
||||
}
|
||||
buf := NewBuffer(file, filename)
|
||||
v.OpenBuffer(buf)
|
||||
return true
|
||||
}
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
// Start moves the viewport to the start of the buffer
|
||||
|
@ -1080,10 +1087,55 @@ func (v *View) Quit() bool {
|
|||
return v.ToggleHelp()
|
||||
}
|
||||
// Make sure not to quit if there are unsaved changes
|
||||
if views[mainView].CanClose("Quit anyway? (yes, no, save) ") {
|
||||
views[mainView].CloseBuffer()
|
||||
screen.Fini()
|
||||
os.Exit(0)
|
||||
if v.CanClose("Quit anyway? (yes, no, save) ") {
|
||||
v.CloseBuffer()
|
||||
if len(tabs) > 1 {
|
||||
if len(tabs[v.TabNum].views) == 1 {
|
||||
tabs = tabs[:v.TabNum+copy(tabs[v.TabNum:], tabs[v.TabNum+1:])]
|
||||
for i, t := range tabs {
|
||||
t.SetNum(i)
|
||||
}
|
||||
if curTab >= len(tabs) {
|
||||
curTab--
|
||||
}
|
||||
if curTab == 0 {
|
||||
CurView().Resize(screen.Size())
|
||||
CurView().matches = Match(CurView())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
screen.Fini()
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (v *View) AddTab() bool {
|
||||
tab := NewTabFromView(NewView(NewBuffer([]byte{}, "")))
|
||||
tab.SetNum(len(tabs))
|
||||
tabs = append(tabs, tab)
|
||||
curTab++
|
||||
if len(tabs) == 2 {
|
||||
for _, t := range tabs {
|
||||
for _, v := range t.views {
|
||||
v.Resize(screen.Size())
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (v *View) PreviousTab() bool {
|
||||
if curTab > 0 {
|
||||
curTab--
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (v *View) NextTab() bool {
|
||||
if curTab < len(tabs)-1 {
|
||||
curTab++
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -51,9 +51,14 @@ type SerializedBuffer struct {
|
|||
func NewBuffer(txt []byte, path string) *Buffer {
|
||||
b := new(Buffer)
|
||||
b.LineArray = NewLineArray(txt)
|
||||
|
||||
b.Path = path
|
||||
b.Name = path
|
||||
|
||||
if path == "" {
|
||||
b.Name = "No name"
|
||||
}
|
||||
|
||||
b.ModTime, _ = GetModTime(b.Path)
|
||||
|
||||
b.EventHandler = NewEventHandler(b)
|
||||
|
|
|
@ -62,8 +62,10 @@ func DefaultCommands() map[string]string {
|
|||
// Set sets an option
|
||||
func Set(args []string) {
|
||||
// Set an option and we have to set it for every view
|
||||
for _, view := range views {
|
||||
SetOption(view, args)
|
||||
for _, tab := range tabs {
|
||||
for _, view := range tab.views {
|
||||
SetOption(view, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,13 +87,13 @@ func Run(args []string) {
|
|||
// Quit closes the main view
|
||||
func Quit(args []string) {
|
||||
// Close the main view
|
||||
views[mainView].Quit()
|
||||
CurView().Quit()
|
||||
}
|
||||
|
||||
// Save saves the buffer in the main view
|
||||
func Save(args []string) {
|
||||
// Save the main view
|
||||
views[mainView].Save()
|
||||
CurView().Save()
|
||||
}
|
||||
|
||||
// Replace runs search and replace
|
||||
|
@ -138,7 +140,7 @@ func Replace(args []string) {
|
|||
return
|
||||
}
|
||||
|
||||
view := views[mainView]
|
||||
view := CurView()
|
||||
|
||||
found := false
|
||||
for {
|
||||
|
|
|
@ -48,14 +48,14 @@ var (
|
|||
L *lua.LState
|
||||
|
||||
// The list of views
|
||||
views []*View
|
||||
// This is the currently open view
|
||||
// It's just an index to the view in the views array
|
||||
mainView int
|
||||
tabs []*Tab
|
||||
// This is the currently open tab
|
||||
// It's just an index to the tab in the tabs array
|
||||
curTab int
|
||||
)
|
||||
|
||||
// LoadInput loads the file input for the editor
|
||||
func LoadInput() (string, []byte, error) {
|
||||
func LoadInput() []*Buffer {
|
||||
// There are a number of ways micro should start given its input
|
||||
|
||||
// 1. If it is given a file in os.Args, it should open that
|
||||
|
@ -72,23 +72,34 @@ func LoadInput() (string, []byte, error) {
|
|||
var filename string
|
||||
var input []byte
|
||||
var err error
|
||||
var buffers []*Buffer
|
||||
|
||||
if len(os.Args) > 1 {
|
||||
// Option 1
|
||||
filename = os.Args[1]
|
||||
// Check that the file exists
|
||||
if _, e := os.Stat(filename); e == nil {
|
||||
input, err = ioutil.ReadFile(filename)
|
||||
for i := 1; i < len(os.Args); i++ {
|
||||
filename = os.Args[i]
|
||||
// Check that the file exists
|
||||
if _, e := os.Stat(filename); e == nil {
|
||||
input, err = ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
TermMessage(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
buffers = append(buffers, NewBuffer(input, filename))
|
||||
}
|
||||
} else if !isatty.IsTerminal(os.Stdin.Fd()) {
|
||||
// Option 2
|
||||
// The input is not a terminal, so something is being piped in
|
||||
// and we should read from stdin
|
||||
input, err = ioutil.ReadAll(os.Stdin)
|
||||
buffers = append(buffers, NewBuffer(input, filename))
|
||||
} else {
|
||||
// Option 3, just open an empty buffer
|
||||
buffers = append(buffers, NewBuffer(input, filename))
|
||||
}
|
||||
|
||||
// Option 3, or just return whatever we got
|
||||
return filename, input, err
|
||||
return buffers
|
||||
}
|
||||
|
||||
// InitConfigDir finds the configuration directory for micro according to the XDG spec.
|
||||
|
@ -170,9 +181,10 @@ func InitScreen() {
|
|||
// RedrawAll redraws everything -- all the views and the messenger
|
||||
func RedrawAll() {
|
||||
messenger.Clear()
|
||||
for _, v := range views {
|
||||
for _, v := range tabs[curTab].views {
|
||||
v.Display()
|
||||
}
|
||||
DisplayTabs()
|
||||
messenger.Display()
|
||||
screen.Show()
|
||||
}
|
||||
|
@ -186,12 +198,6 @@ func main() {
|
|||
os.Exit(0)
|
||||
}
|
||||
|
||||
filename, input, err := LoadInput()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
L = lua.NewState()
|
||||
defer L.Close()
|
||||
|
||||
|
@ -210,8 +216,6 @@ func main() {
|
|||
// Load the help files
|
||||
LoadHelp()
|
||||
|
||||
buf := NewBuffer(input, filename)
|
||||
|
||||
InitScreen()
|
||||
|
||||
// This is just so if we have an error, we can exit cleanly and not completely
|
||||
|
@ -229,17 +233,21 @@ func main() {
|
|||
|
||||
messenger = new(Messenger)
|
||||
messenger.history = make(map[string][]string)
|
||||
views = make([]*View, 1)
|
||||
views[0] = NewView(buf)
|
||||
|
||||
buffers := LoadInput()
|
||||
for _, buf := range buffers {
|
||||
tabs = append(tabs, NewTabFromView(NewView(buf)))
|
||||
}
|
||||
|
||||
L.SetGlobal("OS", luar.New(L, runtime.GOOS))
|
||||
L.SetGlobal("views", luar.New(L, views))
|
||||
L.SetGlobal("mainView", luar.New(L, mainView))
|
||||
L.SetGlobal("tabs", luar.New(L, tabs))
|
||||
L.SetGlobal("curTab", luar.New(L, curTab))
|
||||
L.SetGlobal("messenger", luar.New(L, messenger))
|
||||
L.SetGlobal("GetOption", luar.New(L, GetOption))
|
||||
L.SetGlobal("AddOption", luar.New(L, AddOption))
|
||||
L.SetGlobal("BindKey", luar.New(L, BindKey))
|
||||
L.SetGlobal("MakeCommand", luar.New(L, MakeCommand))
|
||||
L.SetGlobal("CurView", luar.New(L, CurView))
|
||||
|
||||
LoadPlugins()
|
||||
|
||||
|
@ -249,14 +257,17 @@ func main() {
|
|||
|
||||
// Wait for the user's action
|
||||
event := screen.PollEvent()
|
||||
if TabbarHandleMouseEvent(event) {
|
||||
continue
|
||||
}
|
||||
|
||||
if searching {
|
||||
// Since searching is done in real time, we need to redraw every time
|
||||
// there is a new event in the search bar
|
||||
HandleSearchEvent(event, views[mainView])
|
||||
HandleSearchEvent(event, CurView())
|
||||
} else {
|
||||
// Send it to the view
|
||||
views[mainView].HandleEvent(event)
|
||||
CurView().HandleEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -15,13 +15,9 @@ type Statusline struct {
|
|||
// Display draws the statusline to the screen
|
||||
func (sline *Statusline) Display() {
|
||||
// We'll draw the line at the lowest line in the view
|
||||
y := sline.view.height
|
||||
y := sline.view.height + sline.view.y
|
||||
|
||||
file := sline.view.Buf.Name
|
||||
// If the name is empty, use 'No name'
|
||||
if file == "" {
|
||||
file = "No name"
|
||||
}
|
||||
|
||||
// If the buffer is dirty (has been modified) write a little '+'
|
||||
if sline.view.Buf.IsModified {
|
||||
|
|
120
cmd/micro/tab.go
Normal file
120
cmd/micro/tab.go
Normal file
|
@ -0,0 +1,120 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/zyedidia/tcell"
|
||||
)
|
||||
|
||||
type Tab struct {
|
||||
// This contains all the views in this tab
|
||||
// There is generally only one view per tab, but you can have
|
||||
// multiple views with splits
|
||||
views []*View
|
||||
// This is the current view for this tab
|
||||
curView int
|
||||
// Generally this is the name of the current view's buffer
|
||||
name string
|
||||
}
|
||||
|
||||
func NewTabFromView(v *View) *Tab {
|
||||
t := new(Tab)
|
||||
t.views = append(t.views, v)
|
||||
t.views[0].Num = 0
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *Tab) SetNum(num int) {
|
||||
for _, v := range t.views {
|
||||
v.TabNum = num
|
||||
}
|
||||
}
|
||||
|
||||
// CurView returns the current view
|
||||
func CurView() *View {
|
||||
curTab := tabs[curTab]
|
||||
return curTab.views[curTab.curView]
|
||||
}
|
||||
|
||||
func TabbarString() (string, map[int]int) {
|
||||
str := ""
|
||||
indicies := make(map[int]int)
|
||||
indicies[0] = 0
|
||||
for i, t := range tabs {
|
||||
if i == curTab {
|
||||
str += "["
|
||||
} else {
|
||||
str += " "
|
||||
}
|
||||
str += t.views[t.curView].Buf.Name
|
||||
if i == curTab {
|
||||
str += "]"
|
||||
} else {
|
||||
str += " "
|
||||
}
|
||||
indicies[len(str)-1] = i + 1
|
||||
str += " "
|
||||
}
|
||||
return str, indicies
|
||||
}
|
||||
|
||||
func TabbarHandleMouseEvent(event tcell.Event) bool {
|
||||
if len(tabs) <= 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
switch e := event.(type) {
|
||||
case *tcell.EventMouse:
|
||||
button := e.Buttons()
|
||||
if button == tcell.Button1 {
|
||||
x, y := e.Position()
|
||||
if y != 0 {
|
||||
return false
|
||||
}
|
||||
str, indicies := TabbarString()
|
||||
if x >= len(str) {
|
||||
return false
|
||||
}
|
||||
var tabnum int
|
||||
var keys []int
|
||||
for k := range indicies {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Ints(keys)
|
||||
for _, k := range keys {
|
||||
if x <= k {
|
||||
tabnum = indicies[k] - 1
|
||||
break
|
||||
}
|
||||
}
|
||||
curTab = tabnum
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func DisplayTabs() {
|
||||
if len(tabs) <= 1 {
|
||||
return
|
||||
}
|
||||
|
||||
str, _ := TabbarString()
|
||||
|
||||
tabBarStyle := defStyle.Reverse(true)
|
||||
if style, ok := colorscheme["tabbar"]; ok {
|
||||
tabBarStyle = style
|
||||
}
|
||||
|
||||
// Maybe there is a unicode filename?
|
||||
fileRunes := []rune(str)
|
||||
w, _ := screen.Size()
|
||||
for x := 0; x < w; x++ {
|
||||
if x < len(fileRunes) {
|
||||
screen.SetContent(x, 0, fileRunes[x], nil, tabBarStyle)
|
||||
} else {
|
||||
screen.SetContent(x, 0, ' ', nil, tabBarStyle)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,6 +31,9 @@ type View struct {
|
|||
width int
|
||||
height int
|
||||
|
||||
// Where this view is located
|
||||
x, y int
|
||||
|
||||
// How much to offset because of line numbers
|
||||
lineNumOffset int
|
||||
|
||||
|
@ -40,6 +43,11 @@ type View struct {
|
|||
// Is the help text opened in this view
|
||||
helpOpen bool
|
||||
|
||||
// This is the index of this view in the views array
|
||||
Num int
|
||||
// What tab is this view stored in
|
||||
TabNum int
|
||||
|
||||
// Is this view modifiable?
|
||||
Modifiable bool
|
||||
|
||||
|
@ -91,6 +99,8 @@ func NewView(buf *Buffer) *View {
|
|||
func NewViewWidthHeight(buf *Buffer, w, h int) *View {
|
||||
v := new(View)
|
||||
|
||||
v.x, v.y = 0, 0
|
||||
|
||||
v.widthPercent = w
|
||||
v.heightPercent = h
|
||||
v.Resize(screen.Size())
|
||||
|
@ -113,6 +123,13 @@ func NewViewWidthHeight(buf *Buffer, w, h int) *View {
|
|||
func (v *View) Resize(w, h int) {
|
||||
// Always include 1 line for the command line at the bottom
|
||||
h--
|
||||
if len(tabs) > 1 {
|
||||
// Include one line for the tab bar at the top
|
||||
h--
|
||||
v.y = 1
|
||||
} else {
|
||||
v.y = 0
|
||||
}
|
||||
v.width = int(float32(w) * float32(v.widthPercent) / 100)
|
||||
// We subtract 1 for the statusline
|
||||
v.height = int(float32(h) * float32(v.heightPercent) / 100)
|
||||
|
@ -173,6 +190,7 @@ func (v *View) OpenBuffer(buf *Buffer) {
|
|||
v.Topline = 0
|
||||
v.leftCol = 0
|
||||
v.Cursor.ResetSelection()
|
||||
v.Relocate()
|
||||
v.messages = make(map[string][]GutterMessage)
|
||||
|
||||
v.matches = Match(v)
|
||||
|
@ -459,12 +477,12 @@ func (v *View) DisplayView() {
|
|||
}
|
||||
|
||||
for lineN := 0; lineN < v.height; lineN++ {
|
||||
var x int
|
||||
x := v.x
|
||||
// If the buffer is smaller than the view height
|
||||
if lineN+v.Topline >= v.Buf.NumLines {
|
||||
// We have to clear all this space
|
||||
for i := 0; i < v.width; i++ {
|
||||
screen.SetContent(i, lineN, ' ', nil, defStyle)
|
||||
screen.SetContent(i, lineN+v.y, ' ', nil, defStyle)
|
||||
}
|
||||
|
||||
continue
|
||||
|
@ -492,9 +510,9 @@ func (v *View) DisplayView() {
|
|||
gutterStyle = style
|
||||
}
|
||||
}
|
||||
screen.SetContent(x, lineN, '>', nil, gutterStyle)
|
||||
screen.SetContent(x, lineN+v.y, '>', nil, gutterStyle)
|
||||
x++
|
||||
screen.SetContent(x, lineN, '>', nil, gutterStyle)
|
||||
screen.SetContent(x, lineN+v.y, '>', nil, gutterStyle)
|
||||
x++
|
||||
if v.Cursor.Y == lineN+v.Topline {
|
||||
messenger.Message(msg.msg)
|
||||
|
@ -504,9 +522,9 @@ func (v *View) DisplayView() {
|
|||
}
|
||||
}
|
||||
if !msgOnLine {
|
||||
screen.SetContent(x, lineN, ' ', nil, tcell.StyleDefault)
|
||||
screen.SetContent(x, lineN+v.y, ' ', nil, tcell.StyleDefault)
|
||||
x++
|
||||
screen.SetContent(x, lineN, ' ', nil, tcell.StyleDefault)
|
||||
screen.SetContent(x, lineN+v.y, ' ', nil, tcell.StyleDefault)
|
||||
x++
|
||||
if v.Cursor.Y == lineN+v.Topline && messenger.gutterMessage {
|
||||
messenger.Reset()
|
||||
|
@ -525,18 +543,18 @@ func (v *View) DisplayView() {
|
|||
if settings["ruler"] == true {
|
||||
lineNum = strconv.Itoa(lineN + v.Topline + 1)
|
||||
for i := 0; i < maxLineLength-len(lineNum); i++ {
|
||||
screen.SetContent(x, lineN, ' ', nil, lineNumStyle)
|
||||
screen.SetContent(x, lineN+v.y, ' ', nil, lineNumStyle)
|
||||
x++
|
||||
}
|
||||
// Write the actual line number
|
||||
for _, ch := range lineNum {
|
||||
screen.SetContent(x, lineN, ch, nil, lineNumStyle)
|
||||
screen.SetContent(x, lineN+v.y, ch, nil, lineNumStyle)
|
||||
x++
|
||||
}
|
||||
|
||||
if settings["ruler"] == true {
|
||||
// Write the extra space
|
||||
screen.SetContent(x, lineN, ' ', nil, lineNumStyle)
|
||||
screen.SetContent(x, lineN+v.y, ' ', nil, lineNumStyle)
|
||||
x++
|
||||
}
|
||||
}
|
||||
|
@ -592,13 +610,13 @@ func (v *View) DisplayView() {
|
|||
}
|
||||
indentChar := []rune(settings["indentchar"].(string))
|
||||
if x-v.leftCol >= v.lineNumOffset {
|
||||
screen.SetContent(x-v.leftCol, lineN, indentChar[0], nil, lineIndentStyle)
|
||||
screen.SetContent(x-v.leftCol, lineN+v.y, indentChar[0], nil, lineIndentStyle)
|
||||
}
|
||||
tabSize := int(settings["tabsize"].(float64))
|
||||
for i := 0; i < tabSize-1; i++ {
|
||||
x++
|
||||
if x-v.leftCol >= v.lineNumOffset {
|
||||
screen.SetContent(x-v.leftCol, lineN, ' ', nil, lineStyle)
|
||||
screen.SetContent(x-v.leftCol, lineN+v.y, ' ', nil, lineStyle)
|
||||
}
|
||||
}
|
||||
} else if runewidth.RuneWidth(ch) > 1 {
|
||||
|
@ -613,7 +631,7 @@ func (v *View) DisplayView() {
|
|||
}
|
||||
} else {
|
||||
if x-v.leftCol >= v.lineNumOffset {
|
||||
screen.SetContent(x-v.leftCol, lineN, ch, nil, lineStyle)
|
||||
screen.SetContent(x-v.leftCol, lineN+v.y, ch, nil, lineStyle)
|
||||
}
|
||||
}
|
||||
charNum = charNum.Move(1, v.Buf)
|
||||
|
@ -632,7 +650,7 @@ func (v *View) DisplayView() {
|
|||
if style, ok := colorscheme["selection"]; ok {
|
||||
selectStyle = style
|
||||
}
|
||||
screen.SetContent(x-v.leftCol, lineN, ' ', nil, selectStyle)
|
||||
screen.SetContent(x-v.leftCol, lineN+v.y, ' ', nil, selectStyle)
|
||||
x++
|
||||
}
|
||||
|
||||
|
@ -647,7 +665,7 @@ func (v *View) DisplayView() {
|
|||
}
|
||||
}
|
||||
if !(x-v.leftCol < v.lineNumOffset) {
|
||||
screen.SetContent(x-v.leftCol+i, lineN, ' ', nil, lineStyle)
|
||||
screen.SetContent(x+i, lineN+v.y, ' ', nil, lineStyle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -659,7 +677,7 @@ func (v *View) DisplayCursor() {
|
|||
if (v.Cursor.Y-v.Topline < 0 || v.Cursor.Y-v.Topline > v.height-1) || v.Cursor.HasSelection() {
|
||||
screen.HideCursor()
|
||||
} else {
|
||||
screen.ShowCursor(v.Cursor.GetVisualX()+v.lineNumOffset-v.leftCol, v.Cursor.Y-v.Topline)
|
||||
screen.ShowCursor(v.x+v.Cursor.GetVisualX()+v.lineNumOffset-v.leftCol, v.Cursor.Y-v.Topline+v.y)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,9 @@ you can rebind them to your liking.
|
|||
"CtrlD": "DuplicateLine",
|
||||
"CtrlV": "Paste",
|
||||
"CtrlA": "SelectAll",
|
||||
"CtrlT": "AddTab"
|
||||
"CtrlRightSq": "PreviousTab",
|
||||
"CtrlBackslash": "NextTab",
|
||||
"Home": "Start",
|
||||
"End": "End",
|
||||
"PageUp": "CursorPageUp",
|
||||
|
|
|
@ -9,7 +9,7 @@ MakeCommand("goimports", "go_goimports")
|
|||
MakeCommand("gofmt", "go_gofmt")
|
||||
|
||||
function go_onSave()
|
||||
if views[mainView+1].Buf.FileType == "Go" then
|
||||
if CurView().Buf.FileType == "Go" then
|
||||
if GetOption("goimports") then
|
||||
go_goimports()
|
||||
elseif GetOption("gofmt") then
|
||||
|
@ -19,21 +19,21 @@ function go_onSave()
|
|||
end
|
||||
|
||||
function go_gofmt()
|
||||
views[mainView+1]:Save()
|
||||
local handle = io.popen("gofmt -w " .. views[mainView+1].Buf.Path)
|
||||
CurView():Save()
|
||||
local handle = io.popen("gofmt -w " .. CurView().Buf.Path)
|
||||
local result = handle:read("*a")
|
||||
handle:close()
|
||||
|
||||
views[mainView+1]:ReOpen()
|
||||
CurView():ReOpen()
|
||||
end
|
||||
|
||||
function go_goimports()
|
||||
views[mainView+1]:Save()
|
||||
local handle = io.popen("goimports -w " .. views[mainView+1].Buf.Path)
|
||||
CurView():Save()
|
||||
local handle = io.popen("goimports -w " .. CurView().Buf.Path)
|
||||
local result = go_split(handle:read("*a"), ":")
|
||||
handle:close()
|
||||
|
||||
views[mainView+1]:ReOpen()
|
||||
CurView():ReOpen()
|
||||
end
|
||||
|
||||
function go_split(str, sep)
|
||||
|
|
|
@ -4,15 +4,15 @@ end
|
|||
|
||||
function linter_onSave()
|
||||
if GetOption("linter") then
|
||||
local ft = views[mainView+1].Buf.FileType
|
||||
local file = views[mainView+1].Buf.Path
|
||||
local ft = CurView().Buf.FileType
|
||||
local file = CurView().Buf.Path
|
||||
local devnull = "/dev/null"
|
||||
if OS == "windows" then
|
||||
devnull = "NUL"
|
||||
end
|
||||
if ft == "Go" then
|
||||
linter_lint("gobuild", "go build -o " .. devnull, "%f:%l: %m")
|
||||
linter_lint("golint", "golint " .. views[mainView+1].Buf.Path, "%f:%l:%d+: %m")
|
||||
linter_lint("golint", "golint " .. CurView().Buf.Path, "%f:%l:%d+: %m")
|
||||
elseif ft == "Lua" then
|
||||
linter_lint("luacheck", "luacheck --no-color " .. file, "%f:%l:%d+: %m")
|
||||
elseif ft == "Python" then
|
||||
|
@ -27,12 +27,12 @@ function linter_onSave()
|
|||
linter_lint("jshint", "jshint " .. file, "%f: line %l,.+, %m")
|
||||
end
|
||||
else
|
||||
views[mainView+1]:ClearAllGutterMessages()
|
||||
CurView():ClearAllGutterMessages()
|
||||
end
|
||||
end
|
||||
|
||||
function linter_lint(linter, cmd, errorformat)
|
||||
views[mainView+1]:ClearGutterMessages(linter)
|
||||
CurView():ClearGutterMessages(linter)
|
||||
|
||||
local handle = io.popen("(" .. cmd .. ")" .. " 2>&1")
|
||||
local lines = linter_split(handle:read("*a"), "\n")
|
||||
|
@ -44,8 +44,8 @@ function linter_lint(linter, cmd, errorformat)
|
|||
line = line:match("^%s*(.+)%s*$")
|
||||
if string.find(line, regex) then
|
||||
local file, line, msg = string.match(line, regex)
|
||||
if linter_basename(views[mainView+1].Buf.Path) == linter_basename(file) then
|
||||
views[mainView+1]:GutterMessage(linter, tonumber(line), msg, 2)
|
||||
if linter_basename(CurView().Buf.Path) == linter_basename(file) then
|
||||
CurView():GutterMessage(linter, tonumber(line), msg, 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue