"regexp"
"strconv"
"strings"
- "unicode/utf8"
shellquote "github.com/kballard/go-shellquote"
- "github.com/zyedidia/micro/internal/buffer"
- "github.com/zyedidia/micro/internal/config"
- "github.com/zyedidia/micro/internal/screen"
- "github.com/zyedidia/micro/internal/shell"
- "github.com/zyedidia/micro/internal/util"
+ "github.com/zyedidia/micro/v2/internal/buffer"
+ "github.com/zyedidia/micro/v2/internal/clipboard"
+ "github.com/zyedidia/micro/v2/internal/config"
+ "github.com/zyedidia/micro/v2/internal/screen"
+ "github.com/zyedidia/micro/v2/internal/shell"
+ "github.com/zyedidia/micro/v2/internal/util"
)
// A Command contains information about how to execute a command
"cd": {(*BufPane).CdCmd, buffer.FileComplete},
"pwd": {(*BufPane).PwdCmd, nil},
"open": {(*BufPane).OpenCmd, buffer.FileComplete},
+ "tabmove": {(*BufPane).TabMoveCmd, nil},
"tabswitch": {(*BufPane).TabSwitchCmd, nil},
"term": {(*BufPane).TermCmd, nil},
"memusage": {(*BufPane).MemUsageCmd, nil},
}
if h.Buf.Type != buffer.BTLog {
- OpenLogBuf(h)
+ h.OpenLogBuf()
}
config.PluginCommand(buffer.LogBuf, args[0], args[1:])
h.Buf.Insert(h.Cursor.Loc, bout.String())
}
+// TabMoveCmd moves the current tab to a given index (starts at 1). The
+// displaced tabs are moved up.
+func (h *BufPane) TabMoveCmd(args []string) {
+ if len(args) <= 0 {
+ InfoBar.Error("Not enough arguments: provide an index, starting at 1")
+ return
+ }
+
+ if len(args[0]) <= 0 {
+ InfoBar.Error("Invalid argument: empty string")
+ return
+ }
+
+ num, err := strconv.Atoi(args[0])
+ if err != nil {
+ InfoBar.Error("Invalid argument: ", err)
+ return
+ }
+
+ // Preserve sign for relative move, if one exists
+ var shiftDirection byte
+ if strings.Contains("-+", string([]byte{args[0][0]})) {
+ shiftDirection = args[0][0]
+ }
+
+ // Relative positions -> absolute positions
+ idxFrom := Tabs.Active()
+ idxTo := 0
+ offset := util.Abs(num)
+ if shiftDirection == '-' {
+ idxTo = idxFrom - offset
+ } else if shiftDirection == '+' {
+ idxTo = idxFrom + offset
+ } else {
+ idxTo = offset - 1
+ }
+
+ // Restrain position to within the valid range
+ idxTo = util.Clamp(idxTo, 0, len(Tabs.List)-1)
+
+ activeTab := Tabs.List[idxFrom]
+ Tabs.RemoveTab(activeTab.ID())
+ Tabs.List = append(Tabs.List, nil)
+ copy(Tabs.List[idxTo+1:], Tabs.List[idxTo:])
+ Tabs.List[idxTo] = activeTab
+ Tabs.UpdateNames()
+ Tabs.SetActive(idxTo)
+ // InfoBar.Message(fmt.Sprintf("Moved tab from slot %d to %d", idxFrom+1, idxTo+1))
+}
+
// TabSwitchCmd switches to a given tab either by name or by number
func (h *BufPane) TabSwitchCmd(args []string) {
if len(args) > 0 {
// ToggleLogCmd toggles the log view
func (h *BufPane) ToggleLogCmd(args []string) {
if h.Buf.Type != buffer.BTLog {
- OpenLogBuf(h)
+ h.OpenLogBuf()
} else {
h.Quit()
}
if err != nil {
screen.TermMessage(err)
}
- config.InitGlobalSettings()
+ err = config.InitGlobalSettings()
+ if err != nil {
+ screen.TermMessage(err)
+ }
InitBindings()
InitCommands()
if !local {
config.GlobalSettings[option] = nativeValue
+ config.ModifiedSettings[option] = true
if option == "colorscheme" {
// LoadSyntaxFiles()
}
} else if option == "paste" {
screen.Screen.SetPaste(nativeValue.(bool))
+ } else if option == "clipboard" {
+ m := clipboard.SetMethod(nativeValue.(string))
+ err := clipboard.Initialize(m)
+ if err != nil {
+ return err
+ }
} else {
for _, pl := range config.Plugins {
if option == pl.Name {
b.SetOptionNative(option, nativeValue)
}
- return config.WriteSettings(config.ConfigDir + "/settings.json")
+ return config.WriteSettings(filepath.Join(config.ConfigDir, "settings.json"))
}
func SetGlobalOption(option, value string) error {
InfoBar.Error(err)
return
}
+ if line < 0 {
+ line = h.Buf.LinesNum() + 1 + line
+ }
line = util.Clamp(line-1, 0, h.Buf.LinesNum()-1)
- col = util.Clamp(col-1, 0, utf8.RuneCount(h.Buf.LineBytes(line)))
+ col = util.Clamp(col-1, 0, util.CharacterCount(h.Buf.LineBytes(line)))
h.Cursor.GotoLoc(buffer.Loc{col, line})
} else {
line, err := strconv.Atoi(args[0])
InfoBar.Error(err)
return
}
+ if line < 0 {
+ line = h.Buf.LinesNum() + 1 + line
+ }
line = util.Clamp(line-1, 0, h.Buf.LinesNum()-1)
h.Cursor.GotoLoc(buffer.Loc{0, line})
}
nreplaced := 0
start := h.Buf.Start()
- // end := h.Buf.End()
- // if h.Cursor.HasSelection() {
- // start = h.Cursor.CurSelection[0]
- // end = h.Cursor.CurSelection[1]
- // }
+ end := h.Buf.End()
+ selection := h.Cursor.HasSelection()
+ if selection {
+ start = h.Cursor.CurSelection[0]
+ end = h.Cursor.CurSelection[1]
+ }
if all {
- nreplaced = h.Buf.ReplaceRegex(start, h.Buf.End(), regex, replace)
+ nreplaced, _ = h.Buf.ReplaceRegex(start, end, regex, replace)
} else {
inRange := func(l buffer.Loc) bool {
- return l.GreaterEqual(start) && l.LessEqual(h.Buf.End())
+ return l.GreaterEqual(start) && l.LessEqual(end)
}
- searchLoc := start
- searching := true
+ searchLoc := h.Cursor.Loc
var doReplacement func()
doReplacement = func() {
- locs, found, err := h.Buf.FindNext(search, start, h.Buf.End(), searchLoc, true, !noRegex)
+ locs, found, err := h.Buf.FindNext(search, start, end, searchLoc, true, !noRegex)
if err != nil {
InfoBar.Error(err)
return
if !found || !inRange(locs[0]) || !inRange(locs[1]) {
h.Cursor.ResetSelection()
h.Buf.RelocateCursors()
+
return
}
h.Cursor.SetSelectionStart(locs[0])
h.Cursor.SetSelectionEnd(locs[1])
+ h.Cursor.GotoLoc(locs[0])
+
+ h.Relocate()
InfoBar.YNPrompt("Perform replacement (y,n,esc)", func(yes, canceled bool) {
if !canceled && yes {
- h.Buf.Replace(locs[0], locs[1], replaceStr)
+ _, nrunes := h.Buf.ReplaceRegex(locs[0], locs[1], regex, replace)
searchLoc = locs[0]
- searchLoc.X += utf8.RuneCount(replace)
+ searchLoc.X += nrunes + locs[0].Diff(locs[1], h.Buf)
+ if end.Y == locs[1].Y {
+ end = end.Move(nrunes, h.Buf)
+ }
h.Cursor.Loc = searchLoc
nreplaced++
} else if !canceled && !yes {
searchLoc = locs[0]
- searchLoc.X += utf8.RuneCount(replace)
+ searchLoc.X += util.CharacterCount(replace)
} else if canceled {
h.Cursor.ResetSelection()
h.Buf.RelocateCursors()
return
}
- if searching {
- doReplacement()
- }
+ doReplacement()
})
}
doReplacement()
}
h.Buf.RelocateCursors()
+ h.Relocate()
+ var s string
if nreplaced > 1 {
- InfoBar.Message("Replaced ", nreplaced, " occurrences of ", search)
+ s = fmt.Sprintf("Replaced %d occurrences of %s", nreplaced, search)
} else if nreplaced == 1 {
- InfoBar.Message("Replaced ", nreplaced, " occurrence of ", search)
+ s = fmt.Sprintf("Replaced 1 occurrence of %s", search)
} else {
- InfoBar.Message("Nothing matched ", search)
+ s = fmt.Sprintf("Nothing matched %s", search)
}
+
+ if selection {
+ s += " in selection"
+ }
+
+ InfoBar.Message(s)
}
// ReplaceAllCmd replaces search term all at once
func (h *BufPane) TermCmd(args []string) {
ps := h.tab.Panes
+ if !TermEmuSupported {
+ InfoBar.Error("Terminal emulator not supported on this system")
+ return
+ }
+
if len(args) == 0 {
sh := os.Getenv("SHELL")
if sh == "" {
term := func(i int, newtab bool) {
t := new(shell.Terminal)
- t.Start(args, false, true, nil, nil)
+ err := t.Start(args, false, true, nil, nil)
+ if err != nil {
+ InfoBar.Error(err)
+ return
+ }
id := h.ID()
if newtab {
}
v := h.GetView()
- MainTab().Panes[i] = NewTermPane(v.X, v.Y, v.Width, v.Height, t, id, MainTab())
+ tp, err := NewTermPane(v.X, v.Y, v.Width, v.Height, t, id, MainTab())
+ if err != nil {
+ InfoBar.Error(err)
+ return
+ }
+ MainTab().Panes[i] = tp
MainTab().SetActive(i)
}