mirror of
https://github.com/zyedidia/micro.git
synced 2026-04-01 15:47:12 +09:00
Compare commits
42 Commits
v2.0.0-rc2
...
highlight-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
477bdb3dc8 | ||
|
|
d74f40882d | ||
|
|
d965e8de4f | ||
|
|
866b3c9238 | ||
|
|
3252324d24 | ||
|
|
8e7a016917 | ||
|
|
cf41a587a3 | ||
|
|
1dc1c65565 | ||
|
|
97ee344268 | ||
|
|
b658f94e5a | ||
|
|
0abe427026 | ||
|
|
b3e40a2644 | ||
|
|
fa4103f7aa | ||
|
|
17f0eb80cd | ||
|
|
35dfb1830b | ||
|
|
76f09adb48 | ||
|
|
289c7147e4 | ||
|
|
be34e1241c | ||
|
|
83ea8d8be9 | ||
|
|
7c90f4d6f1 | ||
|
|
61a90f7666 | ||
|
|
8d373cde6e | ||
|
|
6a465500bc | ||
|
|
f3e8413e77 | ||
|
|
f2a1e2337f | ||
|
|
c7f36f9480 | ||
|
|
955bde4abc | ||
|
|
afb03aa37f | ||
|
|
6c3814dfac | ||
|
|
d234e9ec41 | ||
|
|
c2c0325384 | ||
|
|
dfb6bc0312 | ||
|
|
0c6a7e2837 | ||
|
|
ddc8bf455e | ||
|
|
2855ae204c | ||
|
|
0bf54ff0e7 | ||
|
|
50ff45c213 | ||
|
|
eb2b546600 | ||
|
|
dc4da37908 | ||
|
|
9333354fc8 | ||
|
|
b557ed2221 | ||
|
|
021f8da6f1 |
54
README.md
54
README.md
@@ -29,7 +29,7 @@ You can also check out the website for Micro at https://micro-editor.github.io.
|
||||
- [MacOS terminal](#macos-terminal)
|
||||
- [Linux clipboard support](#linux-clipboard-support)
|
||||
- [Colors and syntax highlighting](#colors-and-syntax-highlighting)
|
||||
- [Plan9, Cygwin](#plan9-cygwin)
|
||||
- [Plan9, Cygwin, Mingw](#plan9-cygwin-mingw)
|
||||
- [Usage](#usage)
|
||||
- [Documentation and Help](#documentation-and-help)
|
||||
- [Contributing](#contributing)
|
||||
@@ -50,25 +50,20 @@ You can also check out the website for Micro at https://micro-editor.github.io.
|
||||
* Extremely good mouse support
|
||||
* This means mouse dragging to create a selection, double click to select by word, and triple click to select by line
|
||||
* Cross platform (It should work on all the platforms Go runs on)
|
||||
* Note that while Windows is supported, there are still some bugs that need to be worked out
|
||||
* Note that while Windows is supported Mingw/Cygwin is not (see below)
|
||||
* Plugin system (plugins are written in Lua)
|
||||
* Micro has a built-in plugin manager to automatically install, remove, and update all your plugins
|
||||
* Persistent undo
|
||||
* Automatic linting and error notifications
|
||||
* Syntax highlighting (for over [90 languages](runtime/syntax)!)
|
||||
* Syntax highlighting (for over [120 languages](runtime/syntax)!)
|
||||
* Colorscheme support
|
||||
* By default, micro comes with 16, 256, and true color themes.
|
||||
* True color support (set the `MICRO_TRUECOLOR` env variable to 1 to enable it)
|
||||
* Snippets
|
||||
* The snippet plugin can be installed with `> plugin install snippets`
|
||||
* True color support (set the `MICRO_TRUECOLOR` environment variable to 1 to enable it)
|
||||
* Copy and paste with the system clipboard
|
||||
* Small and simple
|
||||
* Easily configurable
|
||||
* Macros
|
||||
* Common editor things such as undo/redo, line numbers, Unicode support, softwrap...
|
||||
|
||||
Although not yet implemented, I hope to add more features such as autocompletion ([#174](https://github.com/zyedidia/micro/issues/174)) or a tree view ([#249](https://github.com/zyedidia/micro/issues/249)) in the future.
|
||||
|
||||
# Installation
|
||||
|
||||
To install micro, you can download a [prebuilt binary](https://github.com/zyedidia/micro/releases), or you can build it from source.
|
||||
@@ -106,29 +101,22 @@ You can install micro using Homebrew on Mac:
|
||||
brew install micro
|
||||
```
|
||||
|
||||
On Windows, you can install micro through [Chocolatey](https://chocolatey.org/) or [Scoop](https://github.com/lukesampson/scoop):
|
||||
|
||||
```
|
||||
choco install micro
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
scoop install micro
|
||||
```
|
||||
|
||||
On Linux, you can install micro through [snap](https://snapcraft.io/docs/core/install)
|
||||
On Debian Linux, you can install micro through [snap](https://snapcraft.io/docs/core/install)
|
||||
|
||||
```
|
||||
snap install micro --classic
|
||||
```
|
||||
|
||||
On OpenBSD, micro is available in the ports tree. It is also available as a binary package.
|
||||
Homebrew and snap are the two "officially" maintained package manager distributions of micro.
|
||||
|
||||
```
|
||||
pkg_add -v micro
|
||||
```
|
||||
Micro is also available through other package managers on Linux such as AUR, Nix, and package managers
|
||||
for other operating systems:
|
||||
|
||||
* Windows: [Chocolatey](https://chocolatey.org) and [Scoop](https://github.com/lukesampson/scoop)
|
||||
* `choco install micro`
|
||||
* `scoop install micro`
|
||||
* OpenBSD: Available in the ports tree and also available as a binary package
|
||||
* `pkd_add -v micro`
|
||||
|
||||
### Building from source
|
||||
|
||||
@@ -148,12 +136,16 @@ anywhere you like (for example `/usr/local/bin`).
|
||||
|
||||
The command `make install` will install the binary to `$GOPATH/bin` or `$GOBIN`.
|
||||
|
||||
You can install directly with `go get` (`go get -u github.com/zyedidia/micro/cmd/micro`) but this isn't recommended because it doesn't build micro with version information.
|
||||
You can install directly with `go get` (`go get github.com/zyedidia/micro/cmd/micro`) but this isn't
|
||||
recommended because it doesn't build micro with version information, and doesn't disable debug mode.
|
||||
|
||||
### MacOS terminal
|
||||
|
||||
If you are using MacOS, you should consider using [iTerm2](http://iterm2.com/) instead of the default Mac terminal. The iTerm2 terminal has much better mouse support as well as better handling of key events. For best keybinding behavior, choose `xterm defaults` under `Preferences->Profiles->Keys->Load Preset`. The newest versions also support true color.
|
||||
|
||||
If you still insist on using the default Mac terminal, be sure to set `Use Option key as Meta key` under
|
||||
`Preferences->Profiles->Keyboard` to use <kbd>option</kbd> as <kbd>alt</kbd>.
|
||||
|
||||
### Linux clipboard support
|
||||
|
||||
On Linux, clipboard support requires the 'xclip' or 'xsel' commands to be installed.
|
||||
@@ -169,7 +161,7 @@ If you don't have xclip or xsel, micro will use an internal clipboard for copy a
|
||||
### Colors and syntax highlighting
|
||||
|
||||
If you open micro and it doesn't seem like syntax highlighting is working, this is probably because
|
||||
you are using a terminal which does not support 256 color. Try changing the colorscheme to `simple`
|
||||
you are using a terminal which does not support 256 colors. Try changing the colorscheme to `simple`
|
||||
by pressing CtrlE in micro and typing `set colorscheme simple`.
|
||||
|
||||
If you are using the default Ubuntu terminal, to enable 256 make sure your `TERM` variable is set
|
||||
@@ -180,9 +172,11 @@ that micro's default colorscheme won't look very good. You can either set
|
||||
the colorscheme to `simple`, or download a better terminal emulator, like
|
||||
mintty.
|
||||
|
||||
### Plan9, Cygwin
|
||||
### Plan9, Cygwin, Mingw
|
||||
|
||||
Please note that micro uses the amazing [tcell library](https://github.com/gdamore/tcell), but this
|
||||
These platforms are unfortunately not supported.
|
||||
|
||||
Micro uses the amazing [tcell library](https://github.com/gdamore/tcell), but this
|
||||
means that micro is restricted to the platforms tcell supports. As a result, micro does not support
|
||||
Plan9, and Cygwin (although this may change in the future). Micro also doesn't support NaCl (but NaCl is deprecated anyways).
|
||||
|
||||
|
||||
@@ -117,6 +117,8 @@ func luaImportMicroBuffer() *lua.LTable {
|
||||
return buffer.NewBufferFromFile(path, buffer.BTDefault)
|
||||
}))
|
||||
ulua.L.SetField(pkg, "ByteOffset", luar.New(ulua.L, buffer.ByteOffset))
|
||||
ulua.L.SetField(pkg, "Log", luar.New(ulua.L, buffer.WriteLog))
|
||||
ulua.L.SetField(pkg, "LogBuf", luar.New(ulua.L, buffer.GetLogBuf))
|
||||
|
||||
return pkg
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
@@ -27,6 +28,7 @@ var (
|
||||
flagVersion = flag.Bool("version", false, "Show the version number and information")
|
||||
flagConfigDir = flag.String("config-dir", "", "Specify a custom location for the configuration directory")
|
||||
flagOptions = flag.Bool("options", false, "Show all option help")
|
||||
flagDebug = flag.Bool("debug", false, "Enable debug mode (prints debug info to ./log.txt)")
|
||||
optionFlags map[string]*string
|
||||
)
|
||||
|
||||
@@ -40,6 +42,8 @@ func InitFlags() {
|
||||
fmt.Println(" \tThis can also be done by opening file:LINE:COL")
|
||||
fmt.Println("-options")
|
||||
fmt.Println(" \tShow all option help")
|
||||
fmt.Println("-debug")
|
||||
fmt.Println(" \tEnable debug mode (enables logging to ./log.txt)")
|
||||
fmt.Println("-version")
|
||||
fmt.Println(" \tShow the version number and information")
|
||||
|
||||
@@ -81,6 +85,10 @@ func InitFlags() {
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if util.Debug == "OFF" && *flagDebug {
|
||||
util.Debug = "ON"
|
||||
}
|
||||
}
|
||||
|
||||
// LoadInput determines which files should be loaded into buffers
|
||||
@@ -143,10 +151,10 @@ func main() {
|
||||
|
||||
var err error
|
||||
|
||||
InitLog()
|
||||
|
||||
InitFlags()
|
||||
|
||||
InitLog()
|
||||
|
||||
err = config.InitConfigDir(*flagConfigDir)
|
||||
if err != nil {
|
||||
screen.TermMessage(err)
|
||||
@@ -173,23 +181,6 @@ func main() {
|
||||
|
||||
screen.Init()
|
||||
|
||||
action.InitBindings()
|
||||
action.InitCommands()
|
||||
|
||||
err = config.InitColorscheme()
|
||||
if err != nil {
|
||||
screen.TermMessage(err)
|
||||
}
|
||||
|
||||
err = config.LoadAllPlugins()
|
||||
if err != nil {
|
||||
screen.TermMessage(err)
|
||||
}
|
||||
err = config.RunPluginFn("init")
|
||||
if err != nil {
|
||||
screen.TermMessage(err)
|
||||
}
|
||||
|
||||
// If we have an error, we can exit cleanly and not completely
|
||||
// mess up the terminal being worked in
|
||||
// In other words we need to shut down tcell before the program crashes
|
||||
@@ -207,7 +198,31 @@ func main() {
|
||||
}
|
||||
}()
|
||||
|
||||
action.InitBindings()
|
||||
action.InitCommands()
|
||||
|
||||
err = config.InitColorscheme()
|
||||
if err != nil {
|
||||
screen.TermMessage(err)
|
||||
}
|
||||
|
||||
err = config.LoadAllPlugins()
|
||||
if err != nil {
|
||||
screen.TermMessage(err)
|
||||
}
|
||||
err = config.RunPluginFn("init")
|
||||
if err != nil {
|
||||
screen.TermMessage(err)
|
||||
}
|
||||
|
||||
b := LoadInput()
|
||||
|
||||
if len(b) == 0 {
|
||||
// No buffers to open
|
||||
screen.Screen.Fini()
|
||||
runtime.Goexit()
|
||||
}
|
||||
|
||||
action.InitTabs(b)
|
||||
action.InitGlobals()
|
||||
|
||||
|
||||
3
go.mod
3
go.mod
@@ -4,6 +4,7 @@ require (
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/go-errors/errors v1.0.1
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/mattn/go-isatty v0.0.11
|
||||
github.com/mattn/go-runewidth v0.0.7
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
@@ -15,7 +16,7 @@ require (
|
||||
github.com/zyedidia/highlight v0.0.0-20170330143449-201131ce5cf5
|
||||
github.com/zyedidia/json5 v0.0.0-20200102012142-2da050b1a98d
|
||||
github.com/zyedidia/pty v2.0.0+incompatible // indirect
|
||||
github.com/zyedidia/tcell v1.4.0
|
||||
github.com/zyedidia/tcell v1.4.2
|
||||
github.com/zyedidia/terminal v0.0.0-20180726154117-533c623e2415
|
||||
golang.org/x/text v0.3.2
|
||||
gopkg.in/yaml.v2 v2.2.7
|
||||
|
||||
6
go.sum
6
go.sum
@@ -12,6 +12,8 @@ github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdk
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
@@ -50,6 +52,10 @@ github.com/zyedidia/pty v2.0.0+incompatible h1:Ou5vXL6tvjst+RV8sUFISbuKDnUJPhnpy
|
||||
github.com/zyedidia/pty v2.0.0+incompatible/go.mod h1:4y9l9yJZNxRa7GB/fB+mmDmGkG3CqmzLf4vUxGGotEA=
|
||||
github.com/zyedidia/tcell v1.4.0 h1:uhAz+bdB3HHlVP2hff3WURkI+pERNwgVfy27oi1Gb2A=
|
||||
github.com/zyedidia/tcell v1.4.0/go.mod h1:HhlbMSCcGX15rFDB+Q1Lk3pKEOocsCUAQC3zhZ9sadA=
|
||||
github.com/zyedidia/tcell v1.4.1 h1:zLci8cg1SLINjwSePZ1yUWnYOnZXMyr4h+zaOvhu5K8=
|
||||
github.com/zyedidia/tcell v1.4.1/go.mod h1:HhlbMSCcGX15rFDB+Q1Lk3pKEOocsCUAQC3zhZ9sadA=
|
||||
github.com/zyedidia/tcell v1.4.2 h1:JWMDs6O1saINPIR5M3kNqlWJwkfnBZeZDZszEJi3BW8=
|
||||
github.com/zyedidia/tcell v1.4.2/go.mod h1:HhlbMSCcGX15rFDB+Q1Lk3pKEOocsCUAQC3zhZ9sadA=
|
||||
github.com/zyedidia/terminal v0.0.0-20180726154117-533c623e2415 h1:752dTQ5OatJ9M5ULK2+9lor+nzyZz+LYDo3WGngg3Rc=
|
||||
github.com/zyedidia/terminal v0.0.0-20180726154117-533c623e2415/go.mod h1:8leT8G0Cm8NoJHdrrKHyR9MirWoF4YW7pZh06B6H+1E=
|
||||
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
package action
|
||||
|
||||
import (
|
||||
"log"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
shellquote "github.com/kballard/go-shellquote"
|
||||
"github.com/zyedidia/clipboard"
|
||||
"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/pkg/shellwords"
|
||||
"github.com/zyedidia/tcell"
|
||||
)
|
||||
|
||||
@@ -283,15 +284,18 @@ func (h *BufPane) SelectWordLeft() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// StartOfLine moves the cursor to the start of the text of the line
|
||||
func (h *BufPane) StartOfText() bool {
|
||||
h.Cursor.Deselect(true)
|
||||
h.Cursor.StartOfText()
|
||||
h.Relocate()
|
||||
return true
|
||||
}
|
||||
|
||||
// StartOfLine moves the cursor to the start of the line
|
||||
func (h *BufPane) StartOfLine() bool {
|
||||
h.Cursor.Deselect(true)
|
||||
h.Cursor.StartOfText()
|
||||
// if h.Cursor.X != 0 {
|
||||
// h.Cursor.Start()
|
||||
// } else {
|
||||
// h.Cursor.StartOfText()
|
||||
// }
|
||||
h.Cursor.Start()
|
||||
h.Relocate()
|
||||
return true
|
||||
}
|
||||
@@ -311,6 +315,17 @@ func (h *BufPane) SelectLine() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// SelectToStartOfText selects to the start of the text on the current line
|
||||
func (h *BufPane) SelectToStartOfText() bool {
|
||||
if !h.Cursor.HasSelection() {
|
||||
h.Cursor.OrigSelection[0] = h.Cursor.Loc
|
||||
}
|
||||
h.Cursor.StartOfText()
|
||||
h.Cursor.SelectTo(h.Cursor.Loc)
|
||||
h.Relocate()
|
||||
return true
|
||||
}
|
||||
|
||||
// SelectToStartOfLine selects to the start of the current line
|
||||
func (h *BufPane) SelectToStartOfLine() bool {
|
||||
if !h.Cursor.HasSelection() {
|
||||
@@ -534,12 +549,14 @@ func (h *BufPane) IndentSelection() bool {
|
||||
tabsize := int(h.Buf.Settings["tabsize"].(float64))
|
||||
indentsize := len(h.Buf.IndentString(tabsize))
|
||||
for y := startY; y <= endY; y++ {
|
||||
h.Buf.Insert(buffer.Loc{X: 0, Y: y}, h.Buf.IndentString(tabsize))
|
||||
if y == startY && start.X > 0 {
|
||||
h.Cursor.SetSelectionStart(start.Move(indentsize, h.Buf))
|
||||
}
|
||||
if y == endY {
|
||||
h.Cursor.SetSelectionEnd(buffer.Loc{X: endX + indentsize + 1, Y: endY})
|
||||
if len(h.Buf.LineBytes(y)) > 0 {
|
||||
h.Buf.Insert(buffer.Loc{X: 0, Y: y}, h.Buf.IndentString(tabsize))
|
||||
if y == startY && start.X > 0 {
|
||||
h.Cursor.SetSelectionStart(start.Move(indentsize, h.Buf))
|
||||
}
|
||||
if y == endY {
|
||||
h.Cursor.SetSelectionEnd(buffer.Loc{X: endX + indentsize + 1, Y: endY})
|
||||
}
|
||||
}
|
||||
}
|
||||
h.Buf.RelocateCursors()
|
||||
@@ -611,6 +628,21 @@ func (h *BufPane) Autocomplete() bool {
|
||||
return b.Autocomplete(buffer.BufferComplete)
|
||||
}
|
||||
|
||||
// CycleAutocompleteBack cycles back in the autocomplete suggestion list
|
||||
func (h *BufPane) CycleAutocompleteBack() bool {
|
||||
if h.Cursor.HasSelection() {
|
||||
return false
|
||||
}
|
||||
log.Println(h.Buf.HasSuggestions)
|
||||
|
||||
if h.Buf.HasSuggestions {
|
||||
h.Buf.CycleAutocomplete(false)
|
||||
log.Println("TRUE")
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// InsertTab inserts a tab or spaces
|
||||
func (h *BufPane) InsertTab() bool {
|
||||
b := h.Buf
|
||||
@@ -636,7 +668,10 @@ func (h *BufPane) Save() bool {
|
||||
if h.Buf.Path == "" {
|
||||
h.SaveAs()
|
||||
} else {
|
||||
h.saveBufToFile(h.Buf.Path, "Save")
|
||||
noPrompt := h.saveBufToFile(h.Buf.Path, "Save")
|
||||
if noPrompt {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
@@ -647,13 +682,20 @@ func (h *BufPane) SaveAs() bool {
|
||||
InfoBar.Prompt("Filename: ", "", "Save", nil, func(resp string, canceled bool) {
|
||||
if !canceled {
|
||||
// the filename might or might not be quoted, so unquote first then join the strings.
|
||||
args, err := shellwords.Split(resp)
|
||||
filename := strings.Join(args, " ")
|
||||
args, err := shellquote.Split(resp)
|
||||
if err != nil {
|
||||
InfoBar.Error("Error parsing arguments: ", err)
|
||||
return
|
||||
}
|
||||
h.saveBufToFile(filename, "SaveAs")
|
||||
if len(args) == 0 {
|
||||
InfoBar.Error("No filename given")
|
||||
return
|
||||
}
|
||||
filename := strings.Join(args, " ")
|
||||
noPrompt := h.saveBufToFile(filename, "SaveAs")
|
||||
if noPrompt {
|
||||
h.completeAction("SaveAs")
|
||||
}
|
||||
}
|
||||
})
|
||||
return false
|
||||
@@ -661,7 +703,7 @@ func (h *BufPane) SaveAs() bool {
|
||||
|
||||
// This function saves the buffer to `filename` and changes the buffer's path and name
|
||||
// to `filename` if the save is successful
|
||||
func (h *BufPane) saveBufToFile(filename string, action string) {
|
||||
func (h *BufPane) saveBufToFile(filename string, action string) bool {
|
||||
err := h.Buf.SaveAs(filename)
|
||||
if err != nil {
|
||||
if strings.HasSuffix(err.Error(), "permission denied") {
|
||||
@@ -678,6 +720,7 @@ func (h *BufPane) saveBufToFile(filename string, action string) {
|
||||
h.completeAction(action)
|
||||
}
|
||||
})
|
||||
return false
|
||||
} else {
|
||||
InfoBar.Error(err)
|
||||
}
|
||||
@@ -685,8 +728,8 @@ func (h *BufPane) saveBufToFile(filename string, action string) {
|
||||
h.Buf.Path = filename
|
||||
h.Buf.SetName(filename)
|
||||
InfoBar.Message("Saved " + filename)
|
||||
h.completeAction(action)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Find opens a prompt and searches forward for the input
|
||||
|
||||
@@ -386,107 +386,3 @@ var keyEvents = map[string]tcell.Key{
|
||||
"PgUp": tcell.KeyPgUp,
|
||||
"PgDown": tcell.KeyPgDn,
|
||||
}
|
||||
|
||||
// DefaultBindings returns a map containing micro's default keybindings
|
||||
func DefaultBindings() map[string]string {
|
||||
return map[string]string{
|
||||
"Up": "CursorUp",
|
||||
"Down": "CursorDown",
|
||||
"Right": "CursorRight",
|
||||
"Left": "CursorLeft",
|
||||
"ShiftUp": "SelectUp",
|
||||
"ShiftDown": "SelectDown",
|
||||
"ShiftLeft": "SelectLeft",
|
||||
"ShiftRight": "SelectRight",
|
||||
"AltLeft": "WordLeft",
|
||||
"AltRight": "WordRight",
|
||||
"AltUp": "MoveLinesUp",
|
||||
"AltDown": "MoveLinesDown",
|
||||
"AltShiftRight": "SelectWordRight",
|
||||
"AltShiftLeft": "SelectWordLeft",
|
||||
"CtrlLeft": "StartOfLine",
|
||||
"CtrlRight": "EndOfLine",
|
||||
"CtrlShiftLeft": "SelectToStartOfLine",
|
||||
"ShiftHome": "SelectToStartOfLine",
|
||||
"CtrlShiftRight": "SelectToEndOfLine",
|
||||
"ShiftEnd": "SelectToEndOfLine",
|
||||
"CtrlUp": "CursorStart",
|
||||
"CtrlDown": "CursorEnd",
|
||||
"CtrlShiftUp": "SelectToStart",
|
||||
"CtrlShiftDown": "SelectToEnd",
|
||||
"Alt-{": "ParagraphPrevious",
|
||||
"Alt-}": "ParagraphNext",
|
||||
"Enter": "InsertNewline",
|
||||
"CtrlH": "Backspace",
|
||||
"Backspace": "Backspace",
|
||||
"Alt-CtrlH": "DeleteWordLeft",
|
||||
"Alt-Backspace": "DeleteWordLeft",
|
||||
"Tab": "Autocomplete|IndentSelection|InsertTab",
|
||||
"Backtab": "OutdentSelection|OutdentLine",
|
||||
"CtrlO": "OpenFile",
|
||||
"CtrlS": "Save",
|
||||
"CtrlF": "Find",
|
||||
"CtrlN": "FindNext",
|
||||
"CtrlP": "FindPrevious",
|
||||
"CtrlZ": "Undo",
|
||||
"CtrlY": "Redo",
|
||||
"CtrlC": "Copy",
|
||||
"CtrlX": "Cut",
|
||||
"CtrlK": "CutLine",
|
||||
"CtrlD": "DuplicateLine",
|
||||
"CtrlV": "Paste",
|
||||
"CtrlA": "SelectAll",
|
||||
"CtrlT": "AddTab",
|
||||
"Alt,": "PreviousTab",
|
||||
"Alt.": "NextTab",
|
||||
"Home": "StartOfLine",
|
||||
"End": "EndOfLine",
|
||||
"CtrlHome": "CursorStart",
|
||||
"CtrlEnd": "CursorEnd",
|
||||
"PageUp": "CursorPageUp",
|
||||
"PageDown": "CursorPageDown",
|
||||
"CtrlPageUp": "PreviousTab",
|
||||
"CtrlPageDown": "NextTab",
|
||||
"CtrlG": "ToggleHelp",
|
||||
"Alt-g": "ToggleKeyMenu",
|
||||
"CtrlR": "ToggleRuler",
|
||||
"CtrlL": "command-edit:goto ",
|
||||
"Delete": "Delete",
|
||||
"CtrlB": "ShellMode",
|
||||
"CtrlQ": "Quit",
|
||||
"CtrlE": "CommandMode",
|
||||
"CtrlW": "NextSplit",
|
||||
"CtrlU": "ToggleMacro",
|
||||
"CtrlJ": "PlayMacro",
|
||||
"Insert": "ToggleOverwriteMode",
|
||||
|
||||
// Emacs-style keybindings
|
||||
"Alt-f": "WordRight",
|
||||
"Alt-b": "WordLeft",
|
||||
"Alt-a": "StartOfLine",
|
||||
"Alt-e": "EndOfLine",
|
||||
// "Alt-p": "CursorUp",
|
||||
// "Alt-n": "CursorDown",
|
||||
|
||||
// Integration with file managers
|
||||
"F2": "Save",
|
||||
"F3": "Find",
|
||||
"F4": "Quit",
|
||||
"F7": "Find",
|
||||
"F10": "Quit",
|
||||
"Esc": "Escape",
|
||||
|
||||
// Mouse bindings
|
||||
"MouseWheelUp": "ScrollUp",
|
||||
"MouseWheelDown": "ScrollDown",
|
||||
"MouseLeft": "MousePress",
|
||||
"MouseMiddle": "PastePrimary",
|
||||
"Ctrl-MouseLeft": "MouseMultiCursor",
|
||||
|
||||
"Alt-n": "SpawnMultiCursor",
|
||||
"Alt-m": "SpawnMultiCursorSelect",
|
||||
"Alt-p": "RemoveMultiCursor",
|
||||
"Alt-c": "RemoveAllMultiCursors",
|
||||
"Alt-x": "SkipMultiCursor",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,7 +355,7 @@ func (h *BufPane) DoKeyEvent(e Event) bool {
|
||||
}
|
||||
|
||||
func (h *BufPane) execAction(action func(*BufPane) bool, name string, cursor int) bool {
|
||||
if name != "Autocomplete" {
|
||||
if name != "Autocomplete" && name != "CycleAutocompleteBack" {
|
||||
h.Buf.HasSuggestions = false
|
||||
}
|
||||
|
||||
@@ -497,6 +497,7 @@ var BufKeyActions = map[string]BufKeyAction{
|
||||
"DeleteWordLeft": (*BufPane).DeleteWordLeft,
|
||||
"SelectLine": (*BufPane).SelectLine,
|
||||
"SelectToStartOfLine": (*BufPane).SelectToStartOfLine,
|
||||
"SelectToStartOfText": (*BufPane).SelectToStartOfText,
|
||||
"SelectToEndOfLine": (*BufPane).SelectToEndOfLine,
|
||||
"ParagraphPrevious": (*BufPane).ParagraphPrevious,
|
||||
"ParagraphNext": (*BufPane).ParagraphNext,
|
||||
@@ -523,6 +524,7 @@ var BufKeyActions = map[string]BufKeyAction{
|
||||
"IndentSelection": (*BufPane).IndentSelection,
|
||||
"OutdentSelection": (*BufPane).OutdentSelection,
|
||||
"Autocomplete": (*BufPane).Autocomplete,
|
||||
"CycleAutocompleteBack": (*BufPane).CycleAutocompleteBack,
|
||||
"OutdentLine": (*BufPane).OutdentLine,
|
||||
"Paste": (*BufPane).Paste,
|
||||
"PastePrimary": (*BufPane).PastePrimary,
|
||||
@@ -536,6 +538,7 @@ var BufKeyActions = map[string]BufKeyAction{
|
||||
"SelectPageDown": (*BufPane).SelectPageDown,
|
||||
"HalfPageUp": (*BufPane).HalfPageUp,
|
||||
"HalfPageDown": (*BufPane).HalfPageDown,
|
||||
"StartOfText": (*BufPane).StartOfText,
|
||||
"StartOfLine": (*BufPane).StartOfLine,
|
||||
"EndOfLine": (*BufPane).EndOfLine,
|
||||
"ToggleHelp": (*BufPane).ToggleHelp,
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
|
||||
luar "layeh.com/gopher-luar"
|
||||
|
||||
shellquote "github.com/kballard/go-shellquote"
|
||||
lua "github.com/yuin/gopher-lua"
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
@@ -21,7 +22,6 @@ import (
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/internal/shell"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/micro/pkg/shellwords"
|
||||
)
|
||||
|
||||
// A Command contains information about how to execute a command
|
||||
@@ -344,11 +344,14 @@ func (h *BufPane) OpenCmd(args []string) {
|
||||
if len(args) > 0 {
|
||||
filename := args[0]
|
||||
// the filename might or might not be quoted, so unquote first then join the strings.
|
||||
args, err := shellwords.Split(filename)
|
||||
args, err := shellquote.Split(filename)
|
||||
if err != nil {
|
||||
InfoBar.Error("Error parsing args ", err)
|
||||
return
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return
|
||||
}
|
||||
filename = strings.Join(args, " ")
|
||||
|
||||
open := func() {
|
||||
@@ -497,6 +500,7 @@ func (h *BufPane) HSplitCmd(args []string) {
|
||||
|
||||
// EvalCmd evaluates a lua expression
|
||||
func (h *BufPane) EvalCmd(args []string) {
|
||||
InfoBar.Error("Eval unsupported")
|
||||
}
|
||||
|
||||
// NewTabCmd opens the given file in a new tab
|
||||
@@ -523,37 +527,56 @@ func (h *BufPane) NewTabCmd(args []string) {
|
||||
}
|
||||
|
||||
func SetGlobalOptionNative(option string, nativeValue interface{}) error {
|
||||
config.GlobalSettings[option] = nativeValue
|
||||
local := false
|
||||
for _, s := range config.LocalSettings {
|
||||
if s == option {
|
||||
local = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if option == "colorscheme" {
|
||||
// LoadSyntaxFiles()
|
||||
config.InitColorscheme()
|
||||
for _, b := range buffer.OpenBuffers {
|
||||
b.UpdateRules()
|
||||
}
|
||||
} else if option == "infobar" || option == "keymenu" {
|
||||
Tabs.Resize()
|
||||
} else if option == "mouse" {
|
||||
if !nativeValue.(bool) {
|
||||
screen.Screen.DisableMouse()
|
||||
if !local {
|
||||
config.GlobalSettings[option] = nativeValue
|
||||
|
||||
if option == "colorscheme" {
|
||||
// LoadSyntaxFiles()
|
||||
config.InitColorscheme()
|
||||
for _, b := range buffer.OpenBuffers {
|
||||
b.UpdateRules()
|
||||
}
|
||||
} else if option == "infobar" || option == "keymenu" {
|
||||
Tabs.Resize()
|
||||
} else if option == "mouse" {
|
||||
if !nativeValue.(bool) {
|
||||
screen.Screen.DisableMouse()
|
||||
} else {
|
||||
screen.Screen.EnableMouse()
|
||||
}
|
||||
// autosave option has been removed
|
||||
// } else if option == "autosave" {
|
||||
// if nativeValue.(float64) > 0 {
|
||||
// config.SetAutoTime(int(nativeValue.(float64)))
|
||||
// config.StartAutoSave()
|
||||
// } else {
|
||||
// config.SetAutoTime(0)
|
||||
// }
|
||||
} else if option == "paste" {
|
||||
screen.Screen.SetPaste(nativeValue.(bool))
|
||||
} else {
|
||||
screen.Screen.EnableMouse()
|
||||
}
|
||||
// } else if option == "autosave" {
|
||||
// if nativeValue.(float64) > 0 {
|
||||
// config.SetAutoTime(int(nativeValue.(float64)))
|
||||
// config.StartAutoSave()
|
||||
// } else {
|
||||
// config.SetAutoTime(0)
|
||||
// }
|
||||
} else {
|
||||
for _, pl := range config.Plugins {
|
||||
if option == pl.Name {
|
||||
if nativeValue.(bool) && !pl.Loaded {
|
||||
pl.Load()
|
||||
pl.Call("init")
|
||||
} else if !nativeValue.(bool) && pl.Loaded {
|
||||
pl.Call("deinit")
|
||||
for _, pl := range config.Plugins {
|
||||
if option == pl.Name {
|
||||
if nativeValue.(bool) && !pl.Loaded {
|
||||
pl.Load()
|
||||
_, err := pl.Call("init")
|
||||
if err != nil && err != config.ErrNoSuchFunction {
|
||||
screen.TermMessage(err)
|
||||
}
|
||||
} else if !nativeValue.(bool) && pl.Loaded {
|
||||
_, err := pl.Call("deinit")
|
||||
if err != nil && err != config.ErrNoSuchFunction {
|
||||
screen.TermMessage(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -703,7 +726,7 @@ func (h *BufPane) UnbindCmd(args []string) {
|
||||
|
||||
// RunCmd runs a shell command in the background
|
||||
func (h *BufPane) RunCmd(args []string) {
|
||||
runf, err := shell.RunBackgroundShell(shellwords.Join(args...))
|
||||
runf, err := shell.RunBackgroundShell(shellquote.Join(args...))
|
||||
if err != nil {
|
||||
InfoBar.Error(err)
|
||||
} else {
|
||||
@@ -950,12 +973,16 @@ func (h *BufPane) TermCmd(args []string) {
|
||||
|
||||
// HandleCommand handles input from the user
|
||||
func (h *BufPane) HandleCommand(input string) {
|
||||
args, err := shellwords.Split(input)
|
||||
args, err := shellquote.Split(input)
|
||||
if err != nil {
|
||||
InfoBar.Error("Error parsing args ", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
inputCmd := args[0]
|
||||
|
||||
if _, ok := commands[inputCmd]; !ok {
|
||||
|
||||
105
internal/action/defaults_darwin.go
Normal file
105
internal/action/defaults_darwin.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package action
|
||||
|
||||
// DefaultBindings returns a map containing micro's default keybindings
|
||||
func DefaultBindings() map[string]string {
|
||||
return map[string]string{
|
||||
"Up": "CursorUp",
|
||||
"Down": "CursorDown",
|
||||
"Right": "CursorRight",
|
||||
"Left": "CursorLeft",
|
||||
"ShiftUp": "SelectUp",
|
||||
"ShiftDown": "SelectDown",
|
||||
"ShiftLeft": "SelectLeft",
|
||||
"ShiftRight": "SelectRight",
|
||||
"AltLeft": "WordLeft",
|
||||
"AltRight": "WordRight",
|
||||
"AltUp": "MoveLinesUp",
|
||||
"AltDown": "MoveLinesDown",
|
||||
"AltShiftRight": "SelectWordRight",
|
||||
"AltShiftLeft": "SelectWordLeft",
|
||||
"CtrlLeft": "StartOfText",
|
||||
"CtrlRight": "EndOfLine",
|
||||
"CtrlShiftLeft": "SelectToStartOfText",
|
||||
"ShiftHome": "SelectToStartOfText",
|
||||
"CtrlShiftRight": "SelectToEndOfLine",
|
||||
"ShiftEnd": "SelectToEndOfLine",
|
||||
"CtrlUp": "CursorStart",
|
||||
"CtrlDown": "CursorEnd",
|
||||
"CtrlShiftUp": "SelectToStart",
|
||||
"CtrlShiftDown": "SelectToEnd",
|
||||
"Alt-{": "ParagraphPrevious",
|
||||
"Alt-}": "ParagraphNext",
|
||||
"Enter": "InsertNewline",
|
||||
"CtrlH": "Backspace",
|
||||
"Backspace": "Backspace",
|
||||
"Alt-CtrlH": "DeleteWordLeft",
|
||||
"Alt-Backspace": "DeleteWordLeft",
|
||||
"Tab": "Autocomplete|IndentSelection|InsertTab",
|
||||
"Backtab": "CycleAutocompleteBack|OutdentSelection|OutdentLine",
|
||||
"CtrlO": "OpenFile",
|
||||
"CtrlS": "Save",
|
||||
"CtrlF": "Find",
|
||||
"CtrlN": "FindNext",
|
||||
"CtrlP": "FindPrevious",
|
||||
"CtrlZ": "Undo",
|
||||
"CtrlY": "Redo",
|
||||
"CtrlC": "Copy",
|
||||
"CtrlX": "Cut",
|
||||
"CtrlK": "CutLine",
|
||||
"CtrlD": "DuplicateLine",
|
||||
"CtrlV": "Paste",
|
||||
"CtrlA": "SelectAll",
|
||||
"CtrlT": "AddTab",
|
||||
"Alt,": "PreviousTab",
|
||||
"Alt.": "NextTab",
|
||||
"Home": "StartOfText",
|
||||
"End": "EndOfLine",
|
||||
"CtrlHome": "CursorStart",
|
||||
"CtrlEnd": "CursorEnd",
|
||||
"PageUp": "CursorPageUp",
|
||||
"PageDown": "CursorPageDown",
|
||||
"CtrlPageUp": "PreviousTab",
|
||||
"CtrlPageDown": "NextTab",
|
||||
"CtrlG": "ToggleHelp",
|
||||
"Alt-g": "ToggleKeyMenu",
|
||||
"CtrlR": "ToggleRuler",
|
||||
"CtrlL": "command-edit:goto ",
|
||||
"Delete": "Delete",
|
||||
"CtrlB": "ShellMode",
|
||||
"CtrlQ": "Quit",
|
||||
"CtrlE": "CommandMode",
|
||||
"CtrlW": "NextSplit",
|
||||
"CtrlU": "ToggleMacro",
|
||||
"CtrlJ": "PlayMacro",
|
||||
"Insert": "ToggleOverwriteMode",
|
||||
|
||||
// Emacs-style keybindings
|
||||
"Alt-f": "WordRight",
|
||||
"Alt-b": "WordLeft",
|
||||
"Alt-a": "StartOfText",
|
||||
"Alt-e": "EndOfLine",
|
||||
// "Alt-p": "CursorUp",
|
||||
// "Alt-n": "CursorDown",
|
||||
|
||||
// Integration with file managers
|
||||
"F2": "Save",
|
||||
"F3": "Find",
|
||||
"F4": "Quit",
|
||||
"F7": "Find",
|
||||
"F10": "Quit",
|
||||
"Esc": "Escape",
|
||||
|
||||
// Mouse bindings
|
||||
"MouseWheelUp": "ScrollUp",
|
||||
"MouseWheelDown": "ScrollDown",
|
||||
"MouseLeft": "MousePress",
|
||||
"MouseMiddle": "PastePrimary",
|
||||
"Ctrl-MouseLeft": "MouseMultiCursor",
|
||||
|
||||
"Alt-n": "SpawnMultiCursor",
|
||||
"Alt-m": "SpawnMultiCursorSelect",
|
||||
"Alt-p": "RemoveMultiCursor",
|
||||
"Alt-c": "RemoveAllMultiCursors",
|
||||
"Alt-x": "SkipMultiCursor",
|
||||
}
|
||||
}
|
||||
107
internal/action/defaults_other.go
Normal file
107
internal/action/defaults_other.go
Normal file
@@ -0,0 +1,107 @@
|
||||
// +build !darwin
|
||||
|
||||
package action
|
||||
|
||||
// DefaultBindings returns a map containing micro's default keybindings
|
||||
func DefaultBindings() map[string]string {
|
||||
return map[string]string{
|
||||
"Up": "CursorUp",
|
||||
"Down": "CursorDown",
|
||||
"Right": "CursorRight",
|
||||
"Left": "CursorLeft",
|
||||
"ShiftUp": "SelectUp",
|
||||
"ShiftDown": "SelectDown",
|
||||
"ShiftLeft": "SelectLeft",
|
||||
"ShiftRight": "SelectRight",
|
||||
"CtrlLeft": "WordLeft",
|
||||
"CtrlRight": "WordRight",
|
||||
"AltUp": "MoveLinesUp",
|
||||
"AltDown": "MoveLinesDown",
|
||||
"CtrlShiftRight": "SelectWordRight",
|
||||
"CtrlShiftLeft": "SelectWordLeft",
|
||||
"AltLeft": "StartOfText",
|
||||
"AltRight": "EndOfLine",
|
||||
"AltShiftLeft": "SelectToStartOfText",
|
||||
"ShiftHome": "SelectToStartOfText",
|
||||
"AltShiftRight": "SelectToEndOfLine",
|
||||
"ShiftEnd": "SelectToEndOfLine",
|
||||
"CtrlUp": "CursorStart",
|
||||
"CtrlDown": "CursorEnd",
|
||||
"CtrlShiftUp": "SelectToStart",
|
||||
"CtrlShiftDown": "SelectToEnd",
|
||||
"Alt-{": "ParagraphPrevious",
|
||||
"Alt-}": "ParagraphNext",
|
||||
"Enter": "InsertNewline",
|
||||
"CtrlH": "Backspace",
|
||||
"Backspace": "Backspace",
|
||||
"Alt-CtrlH": "DeleteWordLeft",
|
||||
"Alt-Backspace": "DeleteWordLeft",
|
||||
"Tab": "Autocomplete|IndentSelection|InsertTab",
|
||||
"Backtab": "CycleAutocompleteBack|OutdentSelection|OutdentLine",
|
||||
"CtrlO": "OpenFile",
|
||||
"CtrlS": "Save",
|
||||
"CtrlF": "Find",
|
||||
"CtrlN": "FindNext",
|
||||
"CtrlP": "FindPrevious",
|
||||
"CtrlZ": "Undo",
|
||||
"CtrlY": "Redo",
|
||||
"CtrlC": "Copy",
|
||||
"CtrlX": "Cut",
|
||||
"CtrlK": "CutLine",
|
||||
"CtrlD": "DuplicateLine",
|
||||
"CtrlV": "Paste",
|
||||
"CtrlA": "SelectAll",
|
||||
"CtrlT": "AddTab",
|
||||
"Alt,": "PreviousTab",
|
||||
"Alt.": "NextTab",
|
||||
"Home": "StartOfText",
|
||||
"End": "EndOfLine",
|
||||
"CtrlHome": "CursorStart",
|
||||
"CtrlEnd": "CursorEnd",
|
||||
"PageUp": "CursorPageUp",
|
||||
"PageDown": "CursorPageDown",
|
||||
"CtrlPageUp": "PreviousTab",
|
||||
"CtrlPageDown": "NextTab",
|
||||
"CtrlG": "ToggleHelp",
|
||||
"Alt-g": "ToggleKeyMenu",
|
||||
"CtrlR": "ToggleRuler",
|
||||
"CtrlL": "command-edit:goto ",
|
||||
"Delete": "Delete",
|
||||
"CtrlB": "ShellMode",
|
||||
"CtrlQ": "Quit",
|
||||
"CtrlE": "CommandMode",
|
||||
"CtrlW": "NextSplit",
|
||||
"CtrlU": "ToggleMacro",
|
||||
"CtrlJ": "PlayMacro",
|
||||
"Insert": "ToggleOverwriteMode",
|
||||
|
||||
// Emacs-style keybindings
|
||||
"Alt-f": "WordRight",
|
||||
"Alt-b": "WordLeft",
|
||||
"Alt-a": "StartOfText",
|
||||
"Alt-e": "EndOfLine",
|
||||
// "Alt-p": "CursorUp",
|
||||
// "Alt-n": "CursorDown",
|
||||
|
||||
// Integration with file managers
|
||||
"F2": "Save",
|
||||
"F3": "Find",
|
||||
"F4": "Quit",
|
||||
"F7": "Find",
|
||||
"F10": "Quit",
|
||||
"Esc": "Escape",
|
||||
|
||||
// Mouse bindings
|
||||
"MouseWheelUp": "ScrollUp",
|
||||
"MouseWheelDown": "ScrollDown",
|
||||
"MouseLeft": "MousePress",
|
||||
"MouseMiddle": "PastePrimary",
|
||||
"Ctrl-MouseLeft": "MouseMultiCursor",
|
||||
|
||||
"Alt-n": "SpawnMultiCursor",
|
||||
"Alt-m": "SpawnMultiCursorSelect",
|
||||
"Alt-p": "RemoveMultiCursor",
|
||||
"Alt-c": "RemoveAllMultiCursors",
|
||||
"Alt-x": "SkipMultiCursor",
|
||||
}
|
||||
}
|
||||
@@ -154,7 +154,6 @@ var InfoOverrides = map[string]InfoKeyAction{
|
||||
"CursorDown": (*InfoPane).CursorDown,
|
||||
"InsertNewline": (*InfoPane).InsertNewline,
|
||||
"Autocomplete": (*InfoPane).Autocomplete,
|
||||
"OutdentLine": (*InfoPane).CycleBack,
|
||||
"Escape": (*InfoPane).Escape,
|
||||
"Quit": (*InfoPane).Quit,
|
||||
"QuitAll": (*InfoPane).QuitAll,
|
||||
@@ -196,13 +195,6 @@ func (h *InfoPane) Autocomplete() {
|
||||
}
|
||||
}
|
||||
|
||||
// CycleBack cycles back in the autocomplete suggestion list
|
||||
func (h *InfoPane) CycleBack() {
|
||||
if h.Buf.HasSuggestions {
|
||||
h.Buf.CycleAutocomplete(false)
|
||||
}
|
||||
}
|
||||
|
||||
// InsertNewline completes the prompt
|
||||
func (h *InfoPane) InsertNewline() {
|
||||
if !h.HasYN {
|
||||
|
||||
@@ -91,6 +91,7 @@ func (t *TabList) Resize() {
|
||||
t.List[0].Node.Resize(w, h-iOffset)
|
||||
t.List[0].Resize()
|
||||
}
|
||||
t.TabWindow.Resize(w, h)
|
||||
}
|
||||
|
||||
// HandleEvent checks for a resize event or a mouse event on the tab bar
|
||||
|
||||
@@ -3,17 +3,20 @@
|
||||
package action
|
||||
|
||||
import (
|
||||
shellquote "github.com/kballard/go-shellquote"
|
||||
"github.com/zyedidia/micro/internal/shell"
|
||||
"github.com/zyedidia/micro/pkg/shellwords"
|
||||
)
|
||||
|
||||
const TermEmuSupported = true
|
||||
|
||||
func RunTermEmulator(h *BufPane, input string, wait bool, getOutput bool, callback string, userargs []interface{}) error {
|
||||
args, err := shellwords.Split(input)
|
||||
args, err := shellquote.Split(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
t := new(shell.Terminal)
|
||||
t.Start(args, getOutput, wait, callback, userargs)
|
||||
|
||||
@@ -81,7 +81,7 @@ func (t *TermPane) HandleEvent(event tcell.Event) {
|
||||
t.WriteString(event.EscSeq())
|
||||
}
|
||||
} else if e, ok := event.(*tcell.EventMouse); e != nil && (!ok || t.State.Mode(terminal.ModeMouseMask)) {
|
||||
t.WriteString(event.EscSeq())
|
||||
// t.WriteString(event.EscSeq())
|
||||
} else if e != nil {
|
||||
x, y := e.Position()
|
||||
v := t.GetView()
|
||||
|
||||
@@ -29,7 +29,7 @@ Options: [r]ecover, [i]gnore: `
|
||||
|
||||
// Backup saves the current buffer to ConfigDir/backups
|
||||
func (b *Buffer) Backup(checkTime bool) error {
|
||||
if !b.Settings["backup"].(bool) || b.Path == "" {
|
||||
if !b.Settings["backup"].(bool) || b.Path == "" || b.Type != BTDefault {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -71,14 +71,14 @@ func (b *Buffer) Backup(checkTime bool) error {
|
||||
}
|
||||
}
|
||||
return
|
||||
})
|
||||
}, false)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveBackup removes any backup file associated with this buffer
|
||||
func (b *Buffer) RemoveBackup() {
|
||||
if !b.Settings["backup"].(bool) || b.Path == "" {
|
||||
if !b.Settings["backup"].(bool) || b.Path == "" || b.Type != BTDefault {
|
||||
return
|
||||
}
|
||||
f := config.ConfigDir + "/backups/" + util.EscapePath(b.AbsPath)
|
||||
@@ -88,7 +88,7 @@ func (b *Buffer) RemoveBackup() {
|
||||
// ApplyBackup applies the corresponding backup file to this buffer (if one exists)
|
||||
// Returns true if a backup was applied
|
||||
func (b *Buffer) ApplyBackup(fsize int64) bool {
|
||||
if b.Settings["backup"].(bool) && len(b.Path) > 0 {
|
||||
if b.Settings["backup"].(bool) && len(b.Path) > 0 && b.Type == BTDefault {
|
||||
backupfile := config.ConfigDir + "/backups/" + util.EscapePath(b.AbsPath)
|
||||
if info, err := os.Stat(backupfile); err == nil {
|
||||
backup, err := os.Open(backupfile)
|
||||
|
||||
@@ -28,8 +28,11 @@ import (
|
||||
const backupTime = 8000
|
||||
|
||||
var (
|
||||
// OpenBuffers is a list of the currently open buffers
|
||||
OpenBuffers []*Buffer
|
||||
LogBuf *Buffer
|
||||
// LogBuf is a reference to the log buffer which can be opened with the
|
||||
// `> log` command
|
||||
LogBuf *Buffer
|
||||
)
|
||||
|
||||
// The BufType defines what kind of buffer this is
|
||||
@@ -41,16 +44,26 @@ type BufType struct {
|
||||
}
|
||||
|
||||
var (
|
||||
// BTDefault is a default buffer
|
||||
BTDefault = BufType{0, false, false, true}
|
||||
BTHelp = BufType{1, true, true, true}
|
||||
BTLog = BufType{2, true, true, false}
|
||||
// BTHelp is a help buffer
|
||||
BTHelp = BufType{1, true, true, true}
|
||||
// BTLog is a log buffer
|
||||
BTLog = BufType{2, true, true, false}
|
||||
// BTScratch is a buffer that cannot be saved (for scratch work)
|
||||
BTScratch = BufType{3, false, true, false}
|
||||
BTRaw = BufType{4, false, true, false}
|
||||
BTInfo = BufType{5, false, true, false}
|
||||
// BTRaw is is a buffer that shows raw terminal events
|
||||
BTRaw = BufType{4, false, true, false}
|
||||
// BTInfo is a buffer for inputting information
|
||||
BTInfo = BufType{5, false, true, false}
|
||||
|
||||
// ErrFileTooLarge is returned when the file is too large to hash
|
||||
// (fastdirty is automatically enabled)
|
||||
ErrFileTooLarge = errors.New("File is too large to hash")
|
||||
)
|
||||
|
||||
// SharedBuffer is a struct containing info that is shared among buffers
|
||||
// that have the same file open
|
||||
type SharedBuffer struct {
|
||||
*LineArray
|
||||
// Stores the last modification time of the file the buffer is pointing to
|
||||
@@ -97,8 +110,13 @@ type Buffer struct {
|
||||
// Name of the buffer on the status line
|
||||
name string
|
||||
|
||||
SyntaxDef *highlight.Def
|
||||
// SyntaxDef represents the syntax highlighting definition being used
|
||||
// This stores the highlighting rules and filetype detection info
|
||||
SyntaxDef *highlight.Def
|
||||
// The Highlighter struct actually performs the highlighting
|
||||
Highlighter *highlight.Highlighter
|
||||
// Modifications is the list of modified regions for syntax highlighting
|
||||
Modifications []Loc
|
||||
|
||||
// Hash of the original buffer -- empty if fastdirty is on
|
||||
origHash [md5.Size]byte
|
||||
@@ -133,7 +151,7 @@ func NewBufferFromFile(path string, btype BufType) (*Buffer, error) {
|
||||
fileInfo, _ := os.Stat(filename)
|
||||
|
||||
if err == nil && fileInfo.IsDir() {
|
||||
return nil, errors.New(filename + " is a directory")
|
||||
return nil, errors.New("Error: " + filename + " is a directory and cannot be opened")
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
@@ -211,7 +229,7 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT
|
||||
b.EventHandler = NewEventHandler(b.SharedBuffer, b.cursors)
|
||||
}
|
||||
|
||||
if b.Settings["readonly"].(bool) {
|
||||
if b.Settings["readonly"].(bool) && b.Type == BTDefault {
|
||||
b.Type.Readonly = true
|
||||
}
|
||||
|
||||
@@ -260,6 +278,8 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT
|
||||
screen.TermMessage(err)
|
||||
}
|
||||
|
||||
b.Modifications = make([]Loc, 0, 10)
|
||||
|
||||
OpenBuffers = append(OpenBuffers, b)
|
||||
|
||||
return b
|
||||
@@ -304,26 +324,44 @@ func (b *Buffer) SetName(s string) {
|
||||
b.name = s
|
||||
}
|
||||
|
||||
// Insert inserts the given string of text at the start location
|
||||
func (b *Buffer) Insert(start Loc, text string) {
|
||||
if !b.Type.Readonly {
|
||||
b.EventHandler.cursors = b.cursors
|
||||
b.EventHandler.active = b.curCursor
|
||||
b.EventHandler.Insert(start, text)
|
||||
|
||||
// b.Modifications is cleared every screen redraw so it's
|
||||
// ok to append duplicates
|
||||
b.Modifications = append(b.Modifications, Loc{start.Y, start.Y + strings.Count(text, "\n")})
|
||||
|
||||
go b.Backup(true)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove removes the characters between the start and end locations
|
||||
func (b *Buffer) Remove(start, end Loc) {
|
||||
if !b.Type.Readonly {
|
||||
b.EventHandler.cursors = b.cursors
|
||||
b.EventHandler.active = b.curCursor
|
||||
b.EventHandler.Remove(start, end)
|
||||
|
||||
b.Modifications = append(b.Modifications, Loc{start.Y, start.Y})
|
||||
|
||||
go b.Backup(true)
|
||||
}
|
||||
}
|
||||
|
||||
// ClearModifications clears the list of modified lines in this buffer
|
||||
// The list of modified lines is used for syntax highlighting so that
|
||||
// we can selectively highlight only the necessary lines
|
||||
// This function should be called every time this buffer is drawn to
|
||||
// the screen
|
||||
func (b *Buffer) ClearModifications() {
|
||||
// clear slice without resetting the cap
|
||||
b.Modifications = b.Modifications[:0]
|
||||
}
|
||||
|
||||
// FileType returns the buffer's filetype
|
||||
func (b *Buffer) FileType() string {
|
||||
return b.Settings["filetype"].(string)
|
||||
@@ -372,6 +410,7 @@ func (b *Buffer) ReOpen() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// RelocateCursors relocates all cursors (makes sure they are in the buffer)
|
||||
func (b *Buffer) RelocateCursors() {
|
||||
for _, c := range b.cursors {
|
||||
c.Relocate()
|
||||
@@ -453,8 +492,11 @@ func (b *Buffer) UpdateRules() {
|
||||
if !b.Type.Syntax {
|
||||
return
|
||||
}
|
||||
syntaxFile := ""
|
||||
ft := b.Settings["filetype"].(string)
|
||||
if ft == "off" {
|
||||
return
|
||||
}
|
||||
syntaxFile := ""
|
||||
var header *highlight.Header
|
||||
for _, f := range config.ListRuntimeFiles(config.RTSyntaxHeader) {
|
||||
data, err := f.Data()
|
||||
@@ -568,12 +610,16 @@ func (b *Buffer) UpdateRules() {
|
||||
}
|
||||
|
||||
if b.Highlighter == nil || syntaxFile != "" {
|
||||
if b.SyntaxDef != nil {
|
||||
b.Settings["filetype"] = b.SyntaxDef.FileType
|
||||
b.Highlighter = highlight.NewHighlighter(b.SyntaxDef)
|
||||
if b.Settings["syntax"].(bool) {
|
||||
b.Highlighter.HighlightStates(b)
|
||||
}
|
||||
b.Settings["filetype"] = b.SyntaxDef.FileType
|
||||
} else {
|
||||
b.SyntaxDef = &highlight.EmptyDef
|
||||
}
|
||||
|
||||
if b.SyntaxDef != nil {
|
||||
b.Highlighter = highlight.NewHighlighter(b.SyntaxDef)
|
||||
if b.Settings["syntax"].(bool) {
|
||||
b.Highlighter.HighlightStates(b)
|
||||
b.Highlighter.HighlightMatches(b, 0, b.End().Y)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -876,3 +922,8 @@ func (b *Buffer) Line(i int) string {
|
||||
func WriteLog(s string) {
|
||||
LogBuf.EventHandler.Insert(LogBuf.End(), s)
|
||||
}
|
||||
|
||||
// GetLogBuf returns the log buffer
|
||||
func GetLogBuf() *Buffer {
|
||||
return LogBuf
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
@@ -26,70 +27,42 @@ 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, enc encoding.Encoding, fn func(io.Writer) error) (err error) {
|
||||
var file *os.File
|
||||
func overwriteFile(name string, enc encoding.Encoding, fn func(io.Writer) error, withSudo bool) (err error) {
|
||||
var writeCloser io.WriteCloser
|
||||
|
||||
if file, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
|
||||
return
|
||||
}
|
||||
if withSudo {
|
||||
cmd := exec.Command(config.GlobalSettings["sucmd"].(string), "dd", "bs=4k", "of="+name)
|
||||
|
||||
defer func() {
|
||||
if e := file.Close(); e != nil && err == nil {
|
||||
err = e
|
||||
}
|
||||
}()
|
||||
if writeCloser, err = cmd.StdinPipe(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
w := transform.NewWriter(file, enc.NewEncoder())
|
||||
// w := bufio.NewWriter(file)
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
go func() {
|
||||
<-c
|
||||
cmd.Process.Kill()
|
||||
}()
|
||||
|
||||
if err = fn(w); err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
screenb := screen.TempFini()
|
||||
if e := cmd.Run(); e != nil && err == nil {
|
||||
err = e
|
||||
}
|
||||
screen.TempStart(screenb)
|
||||
}()
|
||||
} else if writeCloser, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// err = w.Flush()
|
||||
return
|
||||
}
|
||||
w := transform.NewWriter(writeCloser, enc.NewEncoder())
|
||||
err = fn(w)
|
||||
|
||||
// overwriteFileAsRoot executes dd as root and then calls the supplied function
|
||||
// with dd's standard input as an io.Writer object. Dd opens the given file for writing,
|
||||
// truncating it if it exists, and writes what it receives on its standard input to the file.
|
||||
func overwriteFileAsRoot(name string, enc encoding.Encoding, fn func(io.Writer) error) (err error) {
|
||||
cmd := exec.Command(config.GlobalSettings["sucmd"].(string), "dd", "status=none", "bs=4K", "of="+name)
|
||||
var stdin io.WriteCloser
|
||||
if e := writeCloser.Close(); e != nil && err == nil {
|
||||
err = e
|
||||
}
|
||||
|
||||
screenb := screen.TempFini()
|
||||
|
||||
// This is a trap for Ctrl-C so that it doesn't kill micro
|
||||
// Instead we trap Ctrl-C to kill the program we're running
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
go func() {
|
||||
for range c {
|
||||
cmd.Process.Kill()
|
||||
}
|
||||
}()
|
||||
|
||||
if stdin, err = cmd.StdinPipe(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = cmd.Start(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
e := fn(stdin)
|
||||
|
||||
if err = stdin.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = cmd.Wait(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
screen.TempStart(screenb)
|
||||
|
||||
return e
|
||||
return
|
||||
}
|
||||
|
||||
// Save saves the buffer to its default path
|
||||
@@ -118,6 +91,9 @@ func (b *Buffer) saveToFile(filename string, withSudo bool) error {
|
||||
if b.Type.Scratch {
|
||||
return errors.New("Cannot save scratch buffer")
|
||||
}
|
||||
if withSudo && runtime.GOOS == "windows" {
|
||||
return errors.New("Save with sudo not supported on Windows")
|
||||
}
|
||||
|
||||
b.UpdateRules()
|
||||
if b.Settings["rmtrailingws"].(bool) {
|
||||
@@ -201,14 +177,8 @@ func (b *Buffer) saveToFile(filename string, withSudo bool) error {
|
||||
return
|
||||
}
|
||||
|
||||
if withSudo {
|
||||
err = overwriteFileAsRoot(absFilename, enc, fwriter)
|
||||
} else {
|
||||
err = overwriteFile(absFilename, enc, fwriter)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
if err = overwriteFile(absFilename, enc, fwriter, withSudo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !b.Settings["fastdirty"].(bool) {
|
||||
|
||||
@@ -39,9 +39,10 @@ func (b *Buffer) Serialize() error {
|
||||
b.ModTime,
|
||||
})
|
||||
return err
|
||||
})
|
||||
}, false)
|
||||
}
|
||||
|
||||
// Unserialize loads the buffer info from config.ConfigDir/buffers
|
||||
func (b *Buffer) Unserialize() error {
|
||||
// If either savecursor or saveundo is turned on, we need to load the serialized information
|
||||
// from ~/.config/micro/buffers
|
||||
@@ -55,7 +56,7 @@ func (b *Buffer) Unserialize() error {
|
||||
decoder := gob.NewDecoder(file)
|
||||
err = decoder.Decode(&buffer)
|
||||
if err != nil {
|
||||
return errors.New(err.Error() + "\nYou may want to remove the files in ~/.config/micro/buffers (these files store the information for the 'saveundo' and 'savecursor' options) if this problem persists.")
|
||||
return errors.New(err.Error() + "\nYou may want to remove the files in ~/.config/micro/buffers (these files\nstore the information for the 'saveundo' and 'savecursor' options) if\nthis problem persists.\nThis may be caused by upgrading to version 2.0, and removing the 'buffers'\ndirectory will reset the cursor and undo history and solve the problem.")
|
||||
}
|
||||
if b.Settings["savecursor"].(bool) {
|
||||
b.StartCursor = buffer.Cursor
|
||||
|
||||
@@ -35,7 +35,7 @@ func (b *Buffer) SetOptionNative(option string, nativeValue interface{}) error {
|
||||
}
|
||||
} else if option == "encoding" {
|
||||
b.isModified = true
|
||||
} else if option == "readonly" {
|
||||
} else if option == "readonly" && b.Type == BTDefault {
|
||||
b.Type.Readonly = nativeValue.(bool)
|
||||
}
|
||||
|
||||
|
||||
@@ -253,7 +253,7 @@ func PluginAddRuntimeFile(plugin string, filetype RTFiletype, filePath string) e
|
||||
pldir := pl.DirName
|
||||
fullpath := filepath.Join(ConfigDir, "plug", pldir, filePath)
|
||||
if _, err := os.Stat(fullpath); err == nil {
|
||||
AddRuntimeFile(filetype, realFile(fullpath))
|
||||
AddRealRuntimeFile(filetype, realFile(fullpath))
|
||||
} else {
|
||||
fullpath = path.Join("runtime", "plugins", pldir, filePath)
|
||||
AddRuntimeFile(filetype, assetFile(fullpath))
|
||||
@@ -280,5 +280,5 @@ func PluginAddRuntimeFilesFromDirectory(plugin string, filetype RTFiletype, dire
|
||||
|
||||
// PluginAddRuntimeFileFromMemory adds a file to the runtime files for a plugin from a given string
|
||||
func PluginAddRuntimeFileFromMemory(filetype RTFiletype, filename, data string) {
|
||||
AddRuntimeFile(filetype, memoryFile{filename, []byte(data)})
|
||||
AddRealRuntimeFile(filetype, memoryFile{filename, []byte(data)})
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -212,15 +212,23 @@ func DefaultCommonSettings() map[string]interface{} {
|
||||
return commonsettings
|
||||
}
|
||||
|
||||
// a list of settings that should only be globally modified and their
|
||||
// default values
|
||||
var defaultGlobalSettings = map[string]interface{}{
|
||||
// "autosave": float64(0),
|
||||
"colorscheme": "default",
|
||||
"infobar": true,
|
||||
"keymenu": false,
|
||||
"mouse": true,
|
||||
"paste": false,
|
||||
"savehistory": true,
|
||||
"sucmd": "sudo",
|
||||
"termtitle": false,
|
||||
}
|
||||
|
||||
// a list of settings that should never be globally modified
|
||||
var LocalSettings = []string{
|
||||
"filetype",
|
||||
"readonly",
|
||||
}
|
||||
|
||||
// DefaultGlobalSettings returns the default global settings for micro
|
||||
@@ -249,6 +257,7 @@ func DefaultAllSettings() map[string]interface{} {
|
||||
return allsettings
|
||||
}
|
||||
|
||||
// GetNativeValue parses and validates a value for a given option
|
||||
func GetNativeValue(option string, realValue interface{}, value string) (interface{}, error) {
|
||||
var native interface{}
|
||||
kind := reflect.TypeOf(realValue).Kind()
|
||||
|
||||
@@ -188,6 +188,11 @@ func (w *BufWindow) LocFromVisual(svloc buffer.Loc) buffer.Loc {
|
||||
bufHeight--
|
||||
}
|
||||
|
||||
bufWidth := w.Width
|
||||
if w.Buf.Settings["scrollbar"].(bool) && w.Buf.LinesNum() > w.Height {
|
||||
bufWidth--
|
||||
}
|
||||
|
||||
// We need to know the string length of the largest line number
|
||||
// so we can pad appropriately when displaying line numbers
|
||||
maxLineNumLength := len(strconv.Itoa(b.LinesNum()))
|
||||
@@ -259,7 +264,7 @@ func (w *BufWindow) LocFromVisual(svloc buffer.Loc) buffer.Loc {
|
||||
totalwidth += width
|
||||
|
||||
// If we reach the end of the window then we either stop or we wrap for softwrap
|
||||
if vloc.X >= w.Width {
|
||||
if vloc.X >= bufWidth {
|
||||
if !softwrap {
|
||||
break
|
||||
} else {
|
||||
@@ -269,7 +274,9 @@ func (w *BufWindow) LocFromVisual(svloc buffer.Loc) buffer.Loc {
|
||||
}
|
||||
vloc.X = 0
|
||||
// This will draw an empty line number because the current line is wrapped
|
||||
vloc.X += maxLineNumLength + 1
|
||||
if b.Settings["ruler"].(bool) {
|
||||
vloc.X += maxLineNumLength + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -351,6 +358,10 @@ func (w *BufWindow) showCursor(x, y int, main bool) {
|
||||
func (w *BufWindow) displayBuffer() {
|
||||
b := w.Buf
|
||||
|
||||
if w.Height <= 0 || w.Width <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
hasMessage := len(b.Messages) > 0
|
||||
bufHeight := w.Height
|
||||
if w.drawStatus {
|
||||
@@ -363,17 +374,14 @@ func (w *BufWindow) displayBuffer() {
|
||||
}
|
||||
|
||||
if b.Settings["syntax"].(bool) && b.SyntaxDef != nil {
|
||||
for _, c := range b.GetCursors() {
|
||||
// rehighlight starting from where the cursor is
|
||||
start := c.Y
|
||||
if start > 0 && b.Rehighlight(start-1) {
|
||||
b.Highlighter.ReHighlightLine(b, start-1)
|
||||
b.SetRehighlight(start-1, false)
|
||||
for _, r := range b.Modifications {
|
||||
final := -1
|
||||
for i := r.X; i <= r.Y; i++ {
|
||||
final = util.Max(b.Highlighter.ReHighlightStates(b, i), final)
|
||||
}
|
||||
|
||||
b.Highlighter.ReHighlightStates(b, start)
|
||||
b.Highlighter.HighlightMatches(b, w.StartLine, w.StartLine+bufHeight)
|
||||
b.Highlighter.HighlightMatches(b, r.X, final+1)
|
||||
}
|
||||
b.ClearModifications()
|
||||
}
|
||||
|
||||
var matchingBraces []buffer.Loc
|
||||
@@ -568,7 +576,9 @@ func (w *BufWindow) displayBuffer() {
|
||||
}
|
||||
vloc.X = 0
|
||||
// This will draw an empty line number because the current line is wrapped
|
||||
w.drawLineNum(lineNumStyle, true, maxLineNumLength, &vloc, &bloc)
|
||||
if b.Settings["ruler"].(bool) {
|
||||
w.drawLineNum(lineNumStyle, true, maxLineNumLength, &vloc, &bloc)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -594,7 +604,9 @@ func (w *BufWindow) displayBuffer() {
|
||||
screen.SetContent(i+w.X, vloc.Y+w.Y, ' ', nil, curStyle)
|
||||
}
|
||||
|
||||
draw(' ', curStyle, true)
|
||||
if vloc.X != bufWidth {
|
||||
draw(' ', curStyle, true)
|
||||
}
|
||||
|
||||
bloc.X = w.StartCol
|
||||
bloc.Y++
|
||||
|
||||
@@ -25,6 +25,10 @@ func NewTabWindow(w int, y int) *TabWindow {
|
||||
return tw
|
||||
}
|
||||
|
||||
func (w *TabWindow) Resize(width, height int) {
|
||||
w.width = width
|
||||
}
|
||||
|
||||
func (w *TabWindow) LocFromVisual(vloc buffer.Loc) int {
|
||||
x := -w.hscroll
|
||||
|
||||
@@ -45,13 +49,18 @@ func (w *TabWindow) LocFromVisual(vloc buffer.Loc) int {
|
||||
|
||||
func (w *TabWindow) Scroll(amt int) {
|
||||
w.hscroll += amt
|
||||
w.hscroll = util.Clamp(w.hscroll, 0, w.TotalSize()-w.width)
|
||||
s := w.TotalSize()
|
||||
w.hscroll = util.Clamp(w.hscroll, 0, s-w.width)
|
||||
|
||||
if s-w.width <= 0 {
|
||||
w.hscroll = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (w *TabWindow) TotalSize() int {
|
||||
sum := 2
|
||||
for _, n := range w.Names {
|
||||
sum += utf8.RuneCountInString(n) + 4
|
||||
sum += runewidth.StringWidth(n) + 4
|
||||
}
|
||||
return sum - 4
|
||||
}
|
||||
@@ -64,6 +73,7 @@ func (w *TabWindow) SetActive(a int) {
|
||||
w.active = a
|
||||
x := 2
|
||||
s := w.TotalSize()
|
||||
|
||||
for i, n := range w.Names {
|
||||
c := utf8.RuneCountInString(n)
|
||||
if i == a {
|
||||
@@ -76,6 +86,10 @@ func (w *TabWindow) SetActive(a int) {
|
||||
}
|
||||
x += c + 4
|
||||
}
|
||||
|
||||
if s-w.width <= 0 {
|
||||
w.hscroll = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (w *TabWindow) Display() {
|
||||
|
||||
@@ -2,6 +2,7 @@ package shell
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -9,8 +10,8 @@ import (
|
||||
"os/signal"
|
||||
"strings"
|
||||
|
||||
shellquote "github.com/kballard/go-shellquote"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/pkg/shellwords"
|
||||
)
|
||||
|
||||
// ExecCommand executes a command using exec
|
||||
@@ -32,10 +33,13 @@ func ExecCommand(name string, arg ...string) (string, error) {
|
||||
|
||||
// RunCommand executes a shell command and returns the output/error
|
||||
func RunCommand(input string) (string, error) {
|
||||
args, err := shellwords.Split(input)
|
||||
args, err := shellquote.Split(input)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return "", errors.New("No arguments")
|
||||
}
|
||||
inputCmd := args[0]
|
||||
|
||||
return ExecCommand(inputCmd, args[1:]...)
|
||||
@@ -45,10 +49,13 @@ func RunCommand(input string) (string, error) {
|
||||
// It returns a function which will run the command and returns a string
|
||||
// message result
|
||||
func RunBackgroundShell(input string) (func() string, error) {
|
||||
args, err := shellwords.Split(input)
|
||||
args, err := shellquote.Split(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return nil, errors.New("No arguments")
|
||||
}
|
||||
inputCmd := args[0]
|
||||
return func() string {
|
||||
output, err := RunCommand(input)
|
||||
@@ -68,10 +75,13 @@ func RunBackgroundShell(input string) (func() string, error) {
|
||||
|
||||
// RunInteractiveShell runs a shellcommand interactively
|
||||
func RunInteractiveShell(input string, wait bool, getOutput bool) (string, error) {
|
||||
args, err := shellwords.Split(input)
|
||||
args, err := shellquote.Split(input)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return "", errors.New("No arguments")
|
||||
}
|
||||
inputCmd := args[0]
|
||||
|
||||
// Shut down the screen because we're going to interact directly with the shell
|
||||
|
||||
@@ -275,7 +275,6 @@ func MakeRelative(path, base string) (string, error) {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// TODO: consider changing because of snap segfault
|
||||
// ReplaceHome takes a path as input and replaces ~ at the start of the path with the user's
|
||||
// home directory. Does nothing if the path does not start with '~'.
|
||||
func ReplaceHome(path string) (string, error) {
|
||||
|
||||
@@ -68,6 +68,8 @@ func combineLineMatch(src, dst LineMatch) LineMatch {
|
||||
// A State represents the region at the end of a line
|
||||
type State *region
|
||||
|
||||
var EmptyDef = Def{nil, &rules{}}
|
||||
|
||||
// LineStates is an interface for a buffer-like object which can also store the states and matches for every line
|
||||
type LineStates interface {
|
||||
LineBytes(n int) []byte
|
||||
@@ -176,7 +178,7 @@ func (h *Highlighter) highlightRegion(highlights LineMatch, start int, canMatchE
|
||||
return highlights
|
||||
}
|
||||
|
||||
if lineLen == 0 || statesOnly {
|
||||
if lineLen == 0 {
|
||||
if canMatchEnd {
|
||||
h.lastRegion = curRegion
|
||||
}
|
||||
@@ -197,28 +199,32 @@ func (h *Highlighter) highlightRegion(highlights LineMatch, start int, canMatchE
|
||||
}
|
||||
}
|
||||
if firstLoc[0] != lineLen {
|
||||
highlights[start+firstLoc[0]] = firstRegion.limitGroup
|
||||
if !statesOnly {
|
||||
highlights[start+firstLoc[0]] = firstRegion.limitGroup
|
||||
}
|
||||
h.highlightRegion(highlights, start, false, lineNum, sliceEnd(line, firstLoc[0]), curRegion, statesOnly)
|
||||
h.highlightRegion(highlights, start+firstLoc[1], canMatchEnd, lineNum, sliceStart(line, firstLoc[1]), firstRegion, statesOnly)
|
||||
return highlights
|
||||
}
|
||||
|
||||
fullHighlights := make([]Group, lineLen)
|
||||
for i := 0; i < len(fullHighlights); i++ {
|
||||
fullHighlights[i] = curRegion.group
|
||||
}
|
||||
if !statesOnly {
|
||||
fullHighlights := make([]Group, lineLen)
|
||||
for i := 0; i < len(fullHighlights); i++ {
|
||||
fullHighlights[i] = curRegion.group
|
||||
}
|
||||
|
||||
for _, p := range curRegion.rules.patterns {
|
||||
matches := findAllIndex(p.regex, line, start == 0, canMatchEnd)
|
||||
for _, m := range matches {
|
||||
for i := m[0]; i < m[1]; i++ {
|
||||
fullHighlights[i] = p.group
|
||||
for _, p := range curRegion.rules.patterns {
|
||||
matches := findAllIndex(p.regex, line, start == 0, canMatchEnd)
|
||||
for _, m := range matches {
|
||||
for i := m[0]; i < m[1]; i++ {
|
||||
fullHighlights[i] = p.group
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for i, h := range fullHighlights {
|
||||
if i == 0 || h != fullHighlights[i-1] {
|
||||
highlights[start+i] = h
|
||||
for i, h := range fullHighlights {
|
||||
if i == 0 || h != fullHighlights[i-1] {
|
||||
highlights[start+i] = h
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,8 +360,9 @@ func (h *Highlighter) HighlightMatches(input LineStates, startline, endline int)
|
||||
}
|
||||
|
||||
// ReHighlightStates will scan down from `startline` and set the appropriate end of line state
|
||||
// for each line until it comes across the same state in two consecutive lines
|
||||
func (h *Highlighter) ReHighlightStates(input LineStates, startline int) {
|
||||
// for each line until it comes across a line whose state does not change
|
||||
// returns the number of the final line
|
||||
func (h *Highlighter) ReHighlightStates(input LineStates, startline int) int {
|
||||
// lines := input.LineData()
|
||||
|
||||
h.lastRegion = nil
|
||||
@@ -378,9 +385,11 @@ func (h *Highlighter) ReHighlightStates(input LineStates, startline int) {
|
||||
input.SetState(i, curState)
|
||||
|
||||
if curState == lastState {
|
||||
break
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return input.LinesNum() - 1
|
||||
}
|
||||
|
||||
// ReHighlightLine will rehighlight the state and match for a single line
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Yasuhiro Matsumoto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,49 +0,0 @@
|
||||
This is a modified version of `go-shellwords` for the micro editor.
|
||||
|
||||
# go-shellwords
|
||||
|
||||
[](https://coveralls.io/r/mattn/go-shellwords?branch=master)
|
||||
[](https://travis-ci.org/mattn/go-shellwords)
|
||||
|
||||
Parse line as shell words.
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
args, err := shellwords.Parse("./foo --bar=baz")
|
||||
// args should be ["./foo", "--bar=baz"]
|
||||
```
|
||||
|
||||
```go
|
||||
os.Setenv("FOO", "bar")
|
||||
p := shellwords.NewParser()
|
||||
p.ParseEnv = true
|
||||
args, err := p.Parse("./foo $FOO")
|
||||
// args should be ["./foo", "bar"]
|
||||
```
|
||||
|
||||
```go
|
||||
p := shellwords.NewParser()
|
||||
p.ParseBacktick = true
|
||||
args, err := p.Parse("./foo `echo $SHELL`")
|
||||
// args should be ["./foo", "/bin/bash"]
|
||||
```
|
||||
|
||||
```go
|
||||
shellwords.ParseBacktick = true
|
||||
p := shellwords.NewParser()
|
||||
args, err := p.Parse("./foo `echo $SHELL`")
|
||||
// args should be ["./foo", "/bin/bash"]
|
||||
```
|
||||
|
||||
# Thanks
|
||||
|
||||
This is based on cpan module [Parse::CommandLine](https://metacpan.org/pod/Parse::CommandLine).
|
||||
|
||||
# License
|
||||
|
||||
under the MIT License: http://mattn.mit-license.org/2017
|
||||
|
||||
# Author
|
||||
|
||||
Yasuhiro Matsumoto (a.k.a mattn)
|
||||
@@ -1,180 +0,0 @@
|
||||
package shellwords
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var envRe = regexp.MustCompile(`\$({[a-zA-Z0-9_]+}|[a-zA-Z0-9_]+)`)
|
||||
|
||||
func isSpace(r rune) bool {
|
||||
switch r {
|
||||
case ' ', '\t', '\r', '\n':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func replaceEnv(s string) string {
|
||||
return envRe.ReplaceAllStringFunc(s, func(s string) string {
|
||||
s = s[1:]
|
||||
if s[0] == '{' {
|
||||
s = s[1 : len(s)-1]
|
||||
}
|
||||
return os.Getenv(s)
|
||||
})
|
||||
}
|
||||
|
||||
type Parser struct {
|
||||
Position int
|
||||
}
|
||||
|
||||
func NewParser() *Parser {
|
||||
return &Parser{0}
|
||||
}
|
||||
|
||||
func (p *Parser) Parse(line string) ([]string, error) {
|
||||
args := []string{}
|
||||
buf := ""
|
||||
var escaped, doubleQuoted, singleQuoted, backQuote, dollarQuote bool
|
||||
backtick := ""
|
||||
|
||||
pos := -1
|
||||
got := false
|
||||
|
||||
loop:
|
||||
for i, r := range line {
|
||||
if escaped {
|
||||
buf += string(r)
|
||||
escaped = false
|
||||
continue
|
||||
}
|
||||
|
||||
if r == '\\' {
|
||||
if singleQuoted {
|
||||
buf += string(r)
|
||||
} else {
|
||||
escaped = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if isSpace(r) {
|
||||
if singleQuoted || doubleQuoted || backQuote || dollarQuote {
|
||||
buf += string(r)
|
||||
backtick += string(r)
|
||||
} else if got {
|
||||
buf = replaceEnv(buf)
|
||||
args = append(args, buf)
|
||||
buf = ""
|
||||
got = false
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
switch r {
|
||||
case '`':
|
||||
if !singleQuoted && !doubleQuoted && !dollarQuote {
|
||||
if backQuote {
|
||||
out, err := shellRun(backtick)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf = out
|
||||
}
|
||||
backtick = ""
|
||||
backQuote = !backQuote
|
||||
continue
|
||||
backtick = ""
|
||||
backQuote = !backQuote
|
||||
}
|
||||
case ')':
|
||||
if !singleQuoted && !doubleQuoted && !backQuote {
|
||||
if dollarQuote {
|
||||
out, err := shellRun(backtick)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf = out
|
||||
}
|
||||
backtick = ""
|
||||
dollarQuote = !dollarQuote
|
||||
continue
|
||||
backtick = ""
|
||||
dollarQuote = !dollarQuote
|
||||
}
|
||||
case '(':
|
||||
if !singleQuoted && !doubleQuoted && !backQuote {
|
||||
if !dollarQuote && len(buf) > 0 && buf == "$" {
|
||||
dollarQuote = true
|
||||
buf += "("
|
||||
continue
|
||||
} else {
|
||||
return nil, errors.New("invalid command line string")
|
||||
}
|
||||
}
|
||||
case '"':
|
||||
if !singleQuoted && !dollarQuote {
|
||||
doubleQuoted = !doubleQuoted
|
||||
continue
|
||||
}
|
||||
case '\'':
|
||||
if !doubleQuoted && !dollarQuote {
|
||||
singleQuoted = !singleQuoted
|
||||
continue
|
||||
}
|
||||
case ';', '&', '|', '<', '>':
|
||||
if !(escaped || singleQuoted || doubleQuoted || backQuote) {
|
||||
pos = i
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
got = true
|
||||
buf += string(r)
|
||||
if backQuote || dollarQuote {
|
||||
backtick += string(r)
|
||||
}
|
||||
}
|
||||
|
||||
buf = replaceEnv(buf)
|
||||
args = append(args, buf)
|
||||
|
||||
if escaped || singleQuoted || doubleQuoted || backQuote || dollarQuote {
|
||||
return nil, errors.New("invalid command line string")
|
||||
}
|
||||
|
||||
p.Position = pos
|
||||
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func Split(line string) ([]string, error) {
|
||||
return NewParser().Parse(line)
|
||||
}
|
||||
|
||||
func Join(args ...string) string {
|
||||
var buf bytes.Buffer
|
||||
for i, w := range args {
|
||||
if i != 0 {
|
||||
buf.WriteByte(' ')
|
||||
}
|
||||
if w == "" {
|
||||
buf.WriteString("''")
|
||||
continue
|
||||
}
|
||||
|
||||
for _, b := range w {
|
||||
switch b {
|
||||
case ' ', '\t', '\r', '\n':
|
||||
buf.WriteByte('\\')
|
||||
buf.WriteString(string(b))
|
||||
default:
|
||||
buf.WriteString(string(b))
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package shellwords
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func shellRun(line string) (string, error) {
|
||||
shell := os.Getenv("SHELL")
|
||||
b, err := exec.Command(shell, "-c", line).Output()
|
||||
if err != nil {
|
||||
if eerr, ok := err.(*exec.ExitError); ok {
|
||||
b = eerr.Stderr
|
||||
}
|
||||
return "", errors.New(err.Error() + ":" + string(b))
|
||||
}
|
||||
return strings.TrimSpace(string(b)), nil
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package shellwords
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func shellRun(line string) (string, error) {
|
||||
shell := os.Getenv("COMSPEC")
|
||||
b, err := exec.Command(shell, "/c", line).Output()
|
||||
if err != nil {
|
||||
if eerr, ok := err.(*exec.ExitError); ok {
|
||||
b = eerr.Stderr
|
||||
}
|
||||
return "", errors.New(err.Error() + ":" + string(b))
|
||||
}
|
||||
return strings.TrimSpace(string(b)), nil
|
||||
}
|
||||
@@ -2,37 +2,54 @@
|
||||
|
||||
This help page aims to cover two aspects of micro's syntax highlighting engine:
|
||||
|
||||
- How to create colorschemes and use them.
|
||||
- How to create syntax files to add to the list of languages micro can highlight.
|
||||
* How to create colorschemes and use them.
|
||||
* How to create syntax files to add to the list of languages micro can highlight.
|
||||
|
||||
## Colorschemes
|
||||
|
||||
To change your colorscheme, press Ctrl-E in micro to bring up the command
|
||||
To change your colorscheme, press Ctrl-e in micro to bring up the command
|
||||
prompt, and type:
|
||||
|
||||
```
|
||||
set colorscheme monokai
|
||||
set colorscheme twilight
|
||||
```
|
||||
|
||||
(or whichever colorscheme you choose).
|
||||
|
||||
Micro comes with a number of colorschemes by default. Modern terminals tend to
|
||||
have three different kinds of color support. The most common is 256 color where
|
||||
the terminal provides 256 standardized colors (except the first 16 may be configured
|
||||
by the user). A 256-color theme requires a terminal with 256 color support and
|
||||
is the most portable.
|
||||
Micro comes with a number of colorschemes by default. The colorschemes that you
|
||||
can display will depend on what kind of color support your terminal has.
|
||||
|
||||
A 16-color theme uses the 16 user-configurable colors (or 16 default colors on
|
||||
old terminals). These colorschemes are guranteed to work, but won't look great
|
||||
unless the 16 colors are configured to the user's liking. Using a 16-color theme
|
||||
will also preserve the terminal's theme because the terminal usually uses its 16
|
||||
colors for prompts or other coloring.
|
||||
Modern terminals tend to have a palette of 16 user-configurable colors (these
|
||||
colors can often be configured in the terminal preferences), and additional
|
||||
color support comes in three flavors.
|
||||
|
||||
Some terminals support "true color" with 16 million colors (using standard RGB values).
|
||||
There is no one standard for this color support among terminals so this method
|
||||
is not guaranteed to work. Usually truecolor must also be enabled by the user. The
|
||||
colorschemes using true color will look exactly as intended. If true color is not
|
||||
supported, a true color colorscheme will approximate its colors to 256-color.
|
||||
* 16-color: A colorscheme that uses the 16 default colors will always work but
|
||||
will only look good if the 16 default colors have been configured to the user's
|
||||
liking. Using a colorscheme that only uses the 16 colors from the terminal palette
|
||||
will also preserve the terminal's theme from other applications since the terminal
|
||||
will often use those same colors for other applications. Default colorschemes
|
||||
of this type include `simple` and `solarized`.
|
||||
|
||||
* 256-color: Almost all terminals support displaying an additional 240 colors on
|
||||
top of the 16 user-configurable colors (creating 256 colors total). Colorschemes
|
||||
which use 256-color are portable because they will look the same regardless of
|
||||
the configured 16-color palette. However, the color range is fairly limited
|
||||
due to the small number of colors available. Default 256-color colorschemes
|
||||
include `monokai`, `twilight`, `zenburn`, `darcula` and more.
|
||||
|
||||
* true-color: Some terminals support displaying "true color" with 16 million
|
||||
colors using standard RGB values. This mode will be able to support displaying
|
||||
any colorscheme, but it should be noted that the user-configured 16-color palette
|
||||
is ignored when using true-color mode (this means the colors while using the
|
||||
terminal emulator will be slightly off). Not all terminals support true color
|
||||
but at this point most do. True color support in micro is off by default but
|
||||
can be enabled by setting the environment variable `MICRO_TRUECOLOR` to 1.
|
||||
In addition your terminal must support it (usually indicated by setting `$COLORTERM`
|
||||
to `truecolor`).
|
||||
True-color colorschemes in micro typically end with `-tc`, such as `solarized-tc`,
|
||||
`atom-dark-tc`, `material-tc`, etc... If true color is not enabled but a true
|
||||
color colorscheme is used, micro will do its best to approximate the colors
|
||||
to the available 256 colors.
|
||||
|
||||
Here is the list of colorschemes:
|
||||
|
||||
@@ -61,7 +78,9 @@ These may vary widely based on the 16 colors selected for your terminal.
|
||||
|
||||
### True color
|
||||
|
||||
These require terminals that support true color and require `MICRO_TRUECOLOR=1` (this is an environment variable).
|
||||
True color requires your terminal to support it. This means that the environment variable
|
||||
`COLORTERM` should have the value `truecolor`, `24bit`, or `24-bit`. In addition, to enable
|
||||
true color in micro, the environment variable `MICRO_TRUECOLOR` must be set to 1.
|
||||
|
||||
* `solarized-tc`: this is the solarized colorscheme for true color.
|
||||
* `atom-dark-tc`: this colorscheme is based off of Atom's "dark" colorscheme.
|
||||
@@ -75,9 +94,12 @@ These require terminals that support true color and require `MICRO_TRUECOLOR=1`
|
||||
Micro's colorschemes are also extremely simple to create. The default ones can
|
||||
be found [here](https://github.com/zyedidia/micro/tree/master/runtime/colorschemes).
|
||||
|
||||
They are only about 18-30 lines in total.
|
||||
Custom colorschemes should be placed in the `~/.config/micro/colorschemes` directory.
|
||||
|
||||
Basically to create the colorscheme you need to link highlight groups with
|
||||
A number of custom directives are placed in a `.micro` file. Colorschemes are
|
||||
typically only 18-30 lines in total.
|
||||
|
||||
To create the colorscheme you need to link highlight groups with
|
||||
actual colors. This is done using the `color-link` command.
|
||||
|
||||
For example, to highlight all comments in green, you would use the command:
|
||||
@@ -218,7 +240,7 @@ You must start the syntax file by declaring the filetype:
|
||||
filetype: go
|
||||
```
|
||||
|
||||
#### Detect definition
|
||||
### Detect definition
|
||||
|
||||
Then you must provide information about how to detect the filetype:
|
||||
|
||||
@@ -237,7 +259,7 @@ detect:
|
||||
header: "%YAML"
|
||||
```
|
||||
|
||||
#### Syntax rules
|
||||
### Syntax rules
|
||||
|
||||
Next you must provide the syntax highlighting rules. There are two types of
|
||||
rules: patterns and regions. A pattern is matched on a single line and usually a
|
||||
@@ -316,3 +338,16 @@ example, the following is possible for html:
|
||||
rules:
|
||||
- include: "css"
|
||||
```
|
||||
|
||||
## Syntax file headers
|
||||
|
||||
Syntax file headers are an optimization and it is likely you do not need to
|
||||
worry about them.
|
||||
|
||||
Syntax file headers are files that contain only the filetype and the detection
|
||||
regular expressions for a given syntax file. They have a `.hdr` suffix and are
|
||||
used by default only for the pre-installed syntax files. Header files allow micro
|
||||
to parse the syntax files much faster when checking the filetype of a certain
|
||||
file. Custom syntax files may provide header files in `~/.config/micro/syntax` as
|
||||
well but it is not necessary (only do this if you have many (100+) custom syntax
|
||||
files and want to improve performance).
|
||||
|
||||
@@ -1,14 +1,35 @@
|
||||
# Possible commands
|
||||
# Command bar
|
||||
|
||||
You can execute an editor command by pressing `Ctrl-e` followed by the command.
|
||||
Here are the possible commands that you can use.
|
||||
The command bar is opened by pressing Ctrl-e. It is a single-line buffer,
|
||||
meaning that all keybindings from a normal buffer are supported (as well
|
||||
as mouse and selection).
|
||||
|
||||
* `quit`: Quits micro.
|
||||
When running a command, you can use extra syntax that micro will expand before
|
||||
running the command. To use an argument with a space in it, put it in
|
||||
quotes. The command bar parser uses the same rules for parsing arguments that
|
||||
`/bin/sh` would use (single quotes, double quotes, escaping). The command bar
|
||||
does not look up environment variables.
|
||||
|
||||
* `save filename?`: Saves the current buffer. If the filename is provided it
|
||||
will 'save as' the filename.
|
||||
# Commands
|
||||
|
||||
* `replace "search" "value" flags`: This will replace `search` with `value`.
|
||||
Micro provides the following commands that can be executed at the command-bar by
|
||||
pressing `Ctrl-e` and entering the command. Arguments are placed in single
|
||||
quotes here but these are not necessary when entering the command in micro.
|
||||
|
||||
* `bind 'key' 'action'`: creates a keybinding from key to action. See the
|
||||
`keybindings` documentation for more information about binding keys.
|
||||
This command will modify `bindings.json` and overwrite any bindings to
|
||||
`key` that already exist.
|
||||
|
||||
* `help 'topic'?`: opens the corresponding help topic. If no topic is provided
|
||||
opens the default help screen.
|
||||
|
||||
* `save 'filename'?`: saves the current buffer. If the file is provided it
|
||||
will 'save as' the filename.
|
||||
|
||||
* `quit`: quits micro.
|
||||
|
||||
* `replace 'search' 'value' 'flags'?`: This will replace `search` with `value`.
|
||||
The `flags` are optional. Possible flags are:
|
||||
* `-a`: Replace all occurrences at once
|
||||
* `-l`: Do a literal search instead of a regex search
|
||||
@@ -16,71 +37,67 @@ Here are the possible commands that you can use.
|
||||
Note that `search` must be a valid regex (unless `-l` is passed). If one
|
||||
of the arguments does not have any spaces in it, you may omit the quotes.
|
||||
|
||||
* `replaceall "search" "value"`: This will replace `search` with `value` without
|
||||
user confirmation.
|
||||
* `replaceall 'search' 'value'`: this will replace all occurrences of `search`
|
||||
with `value` without user confirmation.
|
||||
|
||||
See `replace` command for more information.
|
||||
|
||||
* `set option value`: sets the option to value. See the `options` help topic for
|
||||
a list of options you can set.
|
||||
* `set 'option' 'value'`: sets the option to value. See the `options` help topic for
|
||||
a list of options you can set. This will modify your `settings.json` with the
|
||||
new value.
|
||||
|
||||
* `setlocal option value`: sets the option to value locally (only in the current
|
||||
buffer).
|
||||
* `setlocal 'option' 'value'`: sets the option to value locally (only in the current
|
||||
buffer). This will *not* modify `settings.json`.
|
||||
|
||||
* `show option`: shows the current value of the given option.
|
||||
* `show 'option'`: shows the current value of the given option.
|
||||
|
||||
* `run sh-command`: runs the given shell command in the background. The
|
||||
* `run 'sh-command'`: runs the given shell command in the background. The
|
||||
command's output will be displayed in one line when it finishes running.
|
||||
|
||||
* `bind key action`: creates a keybinding from key to action. See the sections
|
||||
on keybindings above for more info about what keys and actions are available.
|
||||
|
||||
* `vsplit filename`: opens a vertical split with `filename`. If no filename is
|
||||
* `vsplit 'filename'`: opens a vertical split with `filename`. If no filename is
|
||||
provided, a vertical split is opened with an empty buffer.
|
||||
|
||||
* `hsplit filename`: same as `vsplit` but opens a horizontal split instead of a
|
||||
* `hsplit 'filename'`: same as `vsplit` but opens a horizontal split instead of a
|
||||
vertical split.
|
||||
|
||||
* `tab filename`: opens the given file in a new tab.
|
||||
* `tab 'filename'`: opens the given file in a new tab.
|
||||
|
||||
* `tabswitch tab`: This command will switch to the specified tab. The `tab` can
|
||||
* `tabswitch 'tab'`: This command will switch to the specified tab. The `tab` can
|
||||
either be a tab number, or a name of a tab.
|
||||
|
||||
* `textfilter sh-command`: filters the current selection through a shell command
|
||||
* `textfilter 'sh-command'`: filters the current selection through a shell command
|
||||
as standard input and replaces the selection with the stdout of the shell command.
|
||||
For example, to sort a list of numbers, first select them, and then execute
|
||||
`> textfilter sort -n`.
|
||||
|
||||
* `log`: opens a log of all messages and debug statements.
|
||||
|
||||
* `plugin list`: lists all installed plugins.
|
||||
* `plugin 'list'`: lists all installed plugins.
|
||||
|
||||
* `plugin version pl`: shows version for specified plugin.
|
||||
* `plugin version 'pl'`: shows version for specified plugin.
|
||||
|
||||
* `plugin info pl`: shows additional info for specified plugin.
|
||||
* `plugin info 'pl'`: shows additional info for specified plugin.
|
||||
|
||||
* `reload`: reloads all runtime files.
|
||||
|
||||
* `cd path`: Change the working directory to the given `path`.
|
||||
* `cd 'path'`: Change the working directory to the given `path`.
|
||||
|
||||
* `pwd`: Print the current working directory.
|
||||
|
||||
* `open filename`: Open a file in the current buffer.
|
||||
* `open 'filename'`: Open a file in the current buffer.
|
||||
|
||||
* `reset option`: resets the given option to its default value
|
||||
* `reset 'option'`: resets the given option to its default value
|
||||
|
||||
* `retab`: Replaces all leading tabs with spaces or leading spaces with tabs
|
||||
depending on the value of `tabstospaces`.
|
||||
|
||||
* `raw`: Micro will open a new tab and show the escape sequence for every event
|
||||
* `raw`: micro will open a new tab and show the escape sequence for every event
|
||||
it receives from the terminal. This shows you what micro actually sees from
|
||||
the terminal and helps you see which bindings aren't possible and why. This
|
||||
is most useful for debugging keybindings.
|
||||
|
||||
* `showkey`: Show the action(s) bound to a given key. For example
|
||||
running `> showkey CtrlC` will display `main.(*View).Copy`. Unfortuately
|
||||
showkey does not work well for keys bound to plugin actions. For those
|
||||
it just shows "LuaFunctionBinding."
|
||||
running `> showkey CtrlC` will display `Copy`.
|
||||
|
||||
---
|
||||
|
||||
@@ -89,11 +106,3 @@ The following commands are provided by the default plugins:
|
||||
* `lint`: Lint the current file for errors.
|
||||
|
||||
* `comment`: automatically comment or uncomment current selection or line.
|
||||
|
||||
# Command Parsing
|
||||
|
||||
When running a command, you can use extra syntax that micro will expand before
|
||||
running the command. To use an argument with a space in it, simply put it in
|
||||
quotes. You can also use environment variables in the command bar and they
|
||||
will be expanded to their value. Finally, you can put an expression in backticks
|
||||
and it will be evaluated by the shell beforehand.
|
||||
|
||||
109
runtime/help/copypaste.md
Normal file
109
runtime/help/copypaste.md
Normal file
@@ -0,0 +1,109 @@
|
||||
Copy and paste are essential features in micro but can be
|
||||
confusing to get right especially when running micro over SSH
|
||||
because there are multiple methods. This help document will explain
|
||||
the various methods for copying and pasting, how they work,
|
||||
and the best methods for doing so over SSH.
|
||||
|
||||
# Pasting
|
||||
|
||||
## Micro paste events
|
||||
|
||||
Micro is an application that runs within the terminal. This means
|
||||
that the terminal sends micro events, such as key events, mouse
|
||||
events, resize events, and paste events. Micro's default keybinding
|
||||
for paste is Ctrl-v. This means that when micro receives the key
|
||||
event saying Ctrl-v has been pressed from the terminal, it will
|
||||
attempt to access the system clipboard and effect a paste. The
|
||||
system clipboard will be accessed through `pbpaste` on MacOS
|
||||
(installed by default), `xclip` or `xsel` on Linux (these
|
||||
applications must be installed by the user) or a system call on
|
||||
Windows.
|
||||
|
||||
## Terminal paste events
|
||||
|
||||
For certain keypresses, the terminal will not send an event to
|
||||
micro and will instead do something itself. In this document,
|
||||
such keypresses will be called "terminal keybindings." Often
|
||||
there will be a terminal keybinding for pasting and copying. On
|
||||
MacOS these are Command-v and Command-c and on Linux Ctrl-Shift-v
|
||||
and Ctrl-Shift-c. When the terminal keybinding for paste is
|
||||
executed, your terminal will access the system clipboard, and send
|
||||
micro either a paste event or a list of key events (one key for each
|
||||
character in the paste), depending on whether or not your terminal
|
||||
supports sending paste events (called bracketed paste).
|
||||
|
||||
If your terminal supports bracketed paste, then it will send a paste
|
||||
event and everything will work well. However, if your terminal
|
||||
sends a list of key events, this can cause issues because micro
|
||||
will think you manually entered each character and may add closing
|
||||
brackets or automatic indentation, which will mess up the pasted
|
||||
text. To avoid this, you can temporarily enable the `paste` option
|
||||
while you perform the paste. When paste option is on, micro will
|
||||
aggregate lists of multiple key events into larger paste events.
|
||||
It is a good idea to disable the `paste` option during normal use
|
||||
as occasionally if you are typing quickly, the terminal will send
|
||||
the key events as lists of characters that were in fact manually
|
||||
entered.
|
||||
|
||||
## Pasting over SSH
|
||||
|
||||
When working over SSH, micro is running on the remote machine and
|
||||
your terminal is running on your local machine. Therefore if you
|
||||
would like to paste, using Ctrl-v (micro's keybinding) will not
|
||||
work because when micro attempts to access the system clipboard,
|
||||
it will access the remote machine's clipboard rather than the local
|
||||
machine's clipboard. On the other hand, the terminal keybinding
|
||||
for paste will access your local clipboard and send the text over
|
||||
the network as a paste event, which is what you want.
|
||||
|
||||
## Recommendations
|
||||
|
||||
The recommended method of pasting is the following:
|
||||
|
||||
* If you are not working over SSH, use the micro keybinding (Ctrl-v
|
||||
by default) to perform pastes. If on Linux, install `xclip` or
|
||||
`xsel` beforehand.
|
||||
|
||||
* If you are working over SSH, use the terminal keybinding
|
||||
(Ctrl-Shift-v or Command-v) to perform pastes. If your terminal
|
||||
does not support bracketed paste, when performing a paste first
|
||||
enable the `paste` option, and when finished disable the option.
|
||||
|
||||
# Copying
|
||||
|
||||
Copying follows a similar discussion to the one above about pasting.
|
||||
The primary difference is before performing a copy, the application
|
||||
doing the copy must be told what text needs to be copied.
|
||||
|
||||
Micro has a keybinding (Ctrl-c) for copying and will access the system
|
||||
clipboard to perform the copy. The text that micro will copy into is
|
||||
the text that is currently selected in micro (usually such text is
|
||||
displayed with a white background). When the `mouse` option is enabled,
|
||||
the mouse can be used to select text, as well as other keybindings,
|
||||
such as ShiftLeft, etc...
|
||||
|
||||
The terminal also has a keybinding (Ctrl-Shift-c or Command-c) to perform
|
||||
a copy, and the text that it copies is the text selected by the terminal's
|
||||
selection (*not* micro's selection). To select text with the terminal
|
||||
selection, micro's mouse support must first be disabled by turning the
|
||||
`mouse` option off. The terminal, unlike micro, has no sense of different
|
||||
buffers/splits and what the different characters being displayed are. This
|
||||
means that for copying multiple lines using the terminal selection, you
|
||||
should first disable line numbers (turn off the `ruler` option), otherwise
|
||||
they might be part of your selection and copied.
|
||||
|
||||
## Recommendations
|
||||
|
||||
The recommended method of copying is the following:
|
||||
|
||||
* If you are not working over SSH, use the micro keybinding (Ctrl-c by
|
||||
default) to perform copies. If on Linux, install `xclip` or `xsel`
|
||||
beforehand.
|
||||
|
||||
* If you are working over SSH, use the terminal keybinding
|
||||
(Ctrl-Shift-c or Command-c) to perform copies. You must first disable
|
||||
the `mouse` option to perform a terminal selection, and you may wish
|
||||
to disable line numbers (`ruler` option) and close other splits. This
|
||||
method will only be able to copy characters that are displayed on the
|
||||
screen (you will not be able to copy more than one page's worth of
|
||||
characters).
|
||||
@@ -3,9 +3,9 @@
|
||||
Micro is a terminal-based text editor that aims to be easy to use and intuitive,
|
||||
while also taking advantage of the full capabilities of modern terminals.
|
||||
|
||||
To open the command bar, press CtrlE. This enables a `>` prompt for typing
|
||||
To open the command bar, press Ctrl-e. This enables a `>` prompt for typing
|
||||
commands. From now on when the documentation says to run a command such as
|
||||
`> help`, this means press CtrlE and type `help` (and press enter to execute
|
||||
`> help`, this means press Ctrl-e and type `help` (and press enter to execute
|
||||
the command).
|
||||
|
||||
For a list of the default keybindings run `> help defaultkeys`.
|
||||
@@ -13,7 +13,7 @@ For more information on keybindings see `> help keybindings`.
|
||||
|
||||
## Quick-start
|
||||
|
||||
Press CtrlQ to quit, and CtrlS to save. Press CtrlE to start typing commands and
|
||||
Press Ctrl-q to quit, and Ctrl-s to save. Press Ctrl-e to start typing commands and
|
||||
you can see which commands are available by pressing tab, or by viewing the help
|
||||
topic `> help commands`.
|
||||
|
||||
@@ -23,16 +23,16 @@ what they do. For more info on rebinding keys, see type `> help keybindings`.
|
||||
|
||||
If the colorscheme doesn't look good, you can change it with
|
||||
`> set colorscheme ...`. You can press tab to see the available colorschemes, or
|
||||
see more information with `> help colors`.
|
||||
see more information about colorschemes and syntax highlighting with `> help colors`.
|
||||
|
||||
Press CtrlW to move between splits, and type `> vsplit filename` or
|
||||
Press Ctrl-w to move between splits, and type `> vsplit filename` or
|
||||
`> hsplit filename` to open a new split.
|
||||
|
||||
## Accessing more help
|
||||
|
||||
Micro has a built-in help system much like Vim's (although less extensive).
|
||||
Micro has a built-in help system which can be accessed with the `help` command.
|
||||
|
||||
To use it, press CtrlE to access command mode and type in `help` followed by a
|
||||
To use it, press Ctrl-e to access command mode and type in `help` followed by a
|
||||
topic. Typing `help` followed by nothing will open this page.
|
||||
|
||||
Here are the possible help topics that you can read:
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
|
||||
Micro stores all of the user configuration in its configuration directory.
|
||||
|
||||
Micro uses the `$XDG_CONFIG_HOME/micro` as the configuration directory. As per
|
||||
the XDG spec, if `$XDG_CONFIG_HOME` is not set, `~/.config/micro` is used as
|
||||
the config directory.
|
||||
Micro uses `$MICRO_CONFIG_HOME` as the configuration directory. If this environment
|
||||
variable is not set, it uses `$XDG_CONFIG_HOME/micro` instead. If that
|
||||
environment variable is not set, it uses `~/.config/micro` as the configuration
|
||||
directory. In the documentation, we use `~/.config/micro` to refer to the
|
||||
configuration directory (even if it may in fact be somewhere else if you have
|
||||
set either of the above environment variables).
|
||||
|
||||
Here are the options that you can set:
|
||||
Here are the available options:
|
||||
|
||||
* `autoindent`: when creating a new line, use the same indentation as the
|
||||
previous line.
|
||||
@@ -85,11 +88,11 @@ Here are the options that you can set:
|
||||
|
||||
default value: `unix`
|
||||
|
||||
* `filetype`: sets the filetype for the current buffer. This setting is
|
||||
`local only`.
|
||||
* `filetype`: sets the filetype for the current buffer. Set this option to `off`
|
||||
to completely disable filetype detection.
|
||||
|
||||
default value: this will be automatically set depending on the file you have
|
||||
open
|
||||
default value: `unknown`. This will be automatically overridden depending
|
||||
on the file you open.
|
||||
|
||||
* `ignorecase`: perform case-insensitive searches.
|
||||
|
||||
@@ -128,7 +131,7 @@ Here are the options that you can set:
|
||||
|
||||
default value: `false`
|
||||
|
||||
* `mouse`: whether to enable mouse support. When mouse support is disabled,
|
||||
* `mouse`: mouse support. When mouse support is disabled,
|
||||
usually the terminal will be able to access mouse events which can be useful
|
||||
if you want to copy from the terminal instead of from micro (if over ssh for
|
||||
example, because the terminal has access to the local clipboard and micro
|
||||
@@ -136,7 +139,22 @@ Here are the options that you can set:
|
||||
|
||||
default value: `true`
|
||||
|
||||
* `rmtrailingws`: micro will automatically trim trailing whitespaces at eol.
|
||||
* `paste`: Treat characters sent from the terminal in a single chunk as a paste
|
||||
event rather than a series of manual key presses. If you are pasting using
|
||||
the terminal keybinding (not Ctrl-v, which is micro's default paste keybinding)
|
||||
then it is a good idea to enable this option during the paste and disable
|
||||
once the paste is over. See `> help copypaste` for details about copying
|
||||
and pasting in a terminal environment.
|
||||
|
||||
default value: `false`
|
||||
|
||||
* `readonly`: when enabled, disallows edits to the buffer. It is recommended
|
||||
to only ever set this option locally using `setlocal`.
|
||||
|
||||
default value: `false`
|
||||
|
||||
* `rmtrailingws`: micro will automatically trim trailing whitespaces at ends of
|
||||
lines.
|
||||
|
||||
default value: `false`
|
||||
|
||||
@@ -145,17 +163,19 @@ Here are the options that you can set:
|
||||
default value: `true`
|
||||
|
||||
* `savecursor`: remember where the cursor was last time the file was opened and
|
||||
put it there when you open the file again.
|
||||
put it there when you open the file again. Information is saved to
|
||||
`~/.config/micro/buffers/`
|
||||
|
||||
default value: `false`
|
||||
|
||||
* `savehistory`: remember command history between closing and re-opening
|
||||
micro.
|
||||
micro. Information is saved to `~/.config/micro/buffers/history`.
|
||||
|
||||
default value: `true`
|
||||
|
||||
* `saveundo`: when this option is on, undo is saved even after you close a file
|
||||
so if you close and reopen a file, you can keep undoing.
|
||||
so if you close and reopen a file, you can keep undoing. Information is
|
||||
saved to `~/.config/micro/buffers/`.
|
||||
|
||||
default value: `false`
|
||||
|
||||
@@ -163,8 +183,8 @@ Here are the options that you can set:
|
||||
|
||||
default value: `false`
|
||||
|
||||
* `scrollmargin`: amount of lines you would like to see above and below the
|
||||
cursor.
|
||||
* `scrollmargin`: margin at which the view starts scrolling when the cursor
|
||||
approaches the edge of the view.
|
||||
|
||||
default value: `3`
|
||||
|
||||
@@ -172,23 +192,23 @@ Here are the options that you can set:
|
||||
|
||||
default value: `2`
|
||||
|
||||
* `smartpaste`: should micro add leading whitespace when pasting multiple lines?
|
||||
* `smartpaste`: add leading whitespace when pasting multiple lines.
|
||||
This will attempt to preserve the current indentation level when pasting an
|
||||
unindented block.
|
||||
|
||||
default value: `true`
|
||||
|
||||
* `softwrap`: should micro wrap lines that are too long to fit on the screen.
|
||||
* `softwrap`: wrap lines that are too long to fit on the screen.
|
||||
|
||||
default value: `false`
|
||||
|
||||
* `splitbottom`: when a horizontal split is created, should it be created below
|
||||
the current split?
|
||||
* `splitbottom`: when a horizontal split is created, create it below the
|
||||
current split.
|
||||
|
||||
default value: `true`
|
||||
|
||||
* `splitright`: when a vertical split is created, should it be created to the
|
||||
right of the current split?
|
||||
* `splitright`: when a vertical split is created, create it to the right of the
|
||||
current split.
|
||||
|
||||
default value: `true`
|
||||
|
||||
@@ -201,11 +221,10 @@ Here are the options that you can set:
|
||||
default value: `$(filename) $(modified)($(line),$(col)) $(opt:filetype)
|
||||
$(opt:fileformat) $(opt:encoding)`
|
||||
|
||||
* `statusformatl`: format string definition for the left-justified part of the
|
||||
* `statusformatr`: format string definition for the right-justified part of the
|
||||
statusline.
|
||||
|
||||
default value: `$(bind:ToggleKeyMenu): show bindings, $(bind:ToggleHelp):
|
||||
toggle help`
|
||||
default value: `$(bind:ToggleKeyMenu): bindings, $(bind:ToggleHelp): help`
|
||||
|
||||
* `statusline`: display the status line at the bottom of the screen.
|
||||
|
||||
@@ -217,7 +236,7 @@ Here are the options that you can set:
|
||||
|
||||
default value: `sudo`
|
||||
|
||||
* `syntax`: turns syntax on or off.
|
||||
* `syntax`: enables syntax highlighting.
|
||||
|
||||
default value: `true`
|
||||
|
||||
@@ -227,31 +246,26 @@ Here are the options that you can set:
|
||||
|
||||
default value: `false`
|
||||
|
||||
* `tabsize`: sets the tab size to `option`
|
||||
* `tabsize`: the size in spaces that a tab character should be displayed with.
|
||||
|
||||
default value: `4`
|
||||
|
||||
* `tabstospaces`: use spaces instead of tabs
|
||||
* `tabstospaces`: use spaces instead of tabs.
|
||||
|
||||
default value: `false`
|
||||
|
||||
* `termtitle`: defines whether or not your terminal's title will be set by micro
|
||||
when opened.
|
||||
|
||||
default value: `false`
|
||||
|
||||
* `useprimary` (only useful on *nix): defines whether or not micro will use the
|
||||
* `useprimary` (only useful on unix): defines whether or not micro will use the
|
||||
primary clipboard to copy selections in the background. This does not affect
|
||||
the normal clipboard using Ctrl-C and Ctrl-V.
|
||||
the normal clipboard using Ctrl-c and Ctrl-v.
|
||||
|
||||
default value: `true`
|
||||
|
||||
---
|
||||
|
||||
Plugin options: all plugins come with a special option to enable or disable them. THe option
|
||||
Plugin options: all plugins come with a special option to enable or disable them. The option
|
||||
is a boolean with the same name as the plugin itself.
|
||||
|
||||
Any option you set in the editor will be saved to the file
|
||||
Any option you set in the editor will be saved to the file
|
||||
~/.config/micro/settings.json so, in effect, your configuration file will be
|
||||
created for you. If you'd like to take your configuration with you to another
|
||||
machine, simply copy the settings.json to the other machine.
|
||||
@@ -261,7 +275,8 @@ machine, simply copy the settings.json to the other machine.
|
||||
You can set these settings either globally or locally. Locally means that the
|
||||
setting won't be saved to `~/.config/micro/settings.json` and that it will only
|
||||
be set in the current buffer. Setting an option globally is the default, and
|
||||
will set the option in all buffers.
|
||||
will set the option in all buffers. Use the `setlocal` command to set an option
|
||||
locally rather than globally.
|
||||
|
||||
The `colorscheme` option is global only, and the `filetype` option is local
|
||||
only. To set an option locally, use `setlocal` instead of `set`.
|
||||
|
||||
@@ -9,12 +9,36 @@ plugin's website, dependencies, etc... Here is an example info file
|
||||
from the go plugin, which has the following file structure:
|
||||
|
||||
```
|
||||
~/.config/micro/plug/go-plugin
|
||||
~/.config/micro/plug/go-plugin/
|
||||
go.lua
|
||||
info.json
|
||||
help/
|
||||
go-plugin.md
|
||||
```
|
||||
|
||||
info.json:
|
||||
The `go.lua` file contains the main code for the plugin, though the
|
||||
code may be distributed across multiple Lua files. The `info.json`
|
||||
file contains information about the plugin such as the website,
|
||||
description, version, and any requirements. Plugins may also
|
||||
have additional files which can be added to micro's runtime files,
|
||||
of which there are 5 types:
|
||||
|
||||
* Colorschemes
|
||||
* Syntax files
|
||||
* Help files
|
||||
* Plugin files
|
||||
* Syntax header files
|
||||
|
||||
In most cases, a plugin will want to add help files, but in certain
|
||||
cases a plugin may also want to add colorschemes or syntax files. It
|
||||
is unlikely for a plugin to need to add plugin files at runtime or
|
||||
syntax header files. No directory structure is enforced but keeping
|
||||
runtime files in their own directories is good practice.
|
||||
|
||||
# Info file
|
||||
|
||||
The `info.json` for the Go plugin is the following:
|
||||
|
||||
```
|
||||
{
|
||||
"name": "go",
|
||||
@@ -35,6 +59,10 @@ the website should point to a valid website. The install field should
|
||||
provide info about installing the plugin, or point to a website that
|
||||
provides information.
|
||||
|
||||
Note that the name of the plugin is defined by the name field in
|
||||
the `info.json` and not by the installation path. Some functions micro
|
||||
exposes to plugins require passing the name of the plugin.
|
||||
|
||||
## Lua callbacks
|
||||
|
||||
Plugins use Lua but also have access to many functions both from micro
|
||||
@@ -98,14 +126,14 @@ local micro = import("micro")
|
||||
micro.Log("Hello")
|
||||
```
|
||||
|
||||
The packages and functions are listed below:
|
||||
The packages and functions are listed below (in Go type signatures):
|
||||
|
||||
* `micro`
|
||||
- `TermMessage(msg interface{}...)`
|
||||
- `TermError()`
|
||||
- `InfoBar()`
|
||||
- `Log(msg interface{}...)`
|
||||
- `SetStatusInfoFn`
|
||||
- `SetStatusInfoFn(fn string)`
|
||||
* `micro/config`
|
||||
- `MakeCommand`
|
||||
- `FileComplete`
|
||||
@@ -150,6 +178,8 @@ The packages and functions are listed below:
|
||||
- `BTInfo`
|
||||
- `NewBufferFromFile`
|
||||
- `ByteOffset`
|
||||
- `Log`
|
||||
- `LogBuf`
|
||||
* `micro/util`
|
||||
- `RuneAt`
|
||||
- `GetLeadingWhitespace`
|
||||
@@ -158,9 +188,15 @@ The packages and functions are listed below:
|
||||
|
||||
This may seem like a small list of available functions but some of the objects
|
||||
returned by the functions have many methods. The Lua plugin may access any
|
||||
public methods of an object returned by any of the functions above. For example,
|
||||
with a BufPane object called `bp`, you could called the `Save` function in Lua
|
||||
with `bp:Save()`.
|
||||
public methods of an object returned by any of the functions above. Unfortunately
|
||||
it is not possible to list all the available functions on this page. Please
|
||||
go to the internal documentation at https://godoc.org/github.com/zyedidia/micro
|
||||
to see the full list of available methods. Note that only methods of types that
|
||||
are available to plugins via the functions above can be called from a plugin.
|
||||
For an even more detailed reference see the source code on Github.
|
||||
|
||||
For example, with a BufPane object called `bp`, you could call the `Save` function
|
||||
in Lua with `bp:Save()`.
|
||||
|
||||
Note that Lua uses the `:` syntax to call a function rather than Go's `.` syntax.
|
||||
|
||||
@@ -222,99 +258,54 @@ errors
|
||||
time
|
||||
```
|
||||
|
||||
For documentation for each of these functions, you can simply look
|
||||
through the Go standard library documentation.
|
||||
For documentation for each of these functions, see the Go standard
|
||||
library documentation at https://golang.org/pkg/ (for the packages
|
||||
exposed to micro plugins). The Lua standard library is also available
|
||||
to plugins though it is rather small.
|
||||
|
||||
## Adding help files, syntax files, or colorschemes in your plugin
|
||||
|
||||
You can use the `AddRuntimeFile(name, type, path string)` function to add
|
||||
various kinds of files to your plugin. For example, if you'd like to add a help
|
||||
topic to your plugin called `test`, you would create a `test.md` file, and call
|
||||
the function:
|
||||
You can use the `AddRuntimeFile(name string, type config.RTFiletype, path string)`
|
||||
function to add various kinds of files to your plugin. For example, if you'd
|
||||
like to add a help topic to your plugin called `test`, you would create a
|
||||
`test.md` file, and call the function:
|
||||
|
||||
```lua
|
||||
AddRuntimeFile("test", "help", "test.md")
|
||||
config = import("micro/config")
|
||||
config.AddRuntimeFile("test", config.RTHelp, "test.md")
|
||||
```
|
||||
|
||||
Use `AddRuntimeFilesFromDirectory(name, type, dir, pattern)` to add a number of
|
||||
files to the runtime. To read the content of a runtime file use
|
||||
`ReadRuntimeFile(fileType, name string)` or `ListRuntimeFiles(fileType string)`
|
||||
for all runtime files.
|
||||
|
||||
## Autocomplete command arguments
|
||||
|
||||
See this example to learn how to use `MakeCompletion` and `MakeCommand`
|
||||
|
||||
```lua
|
||||
local function StartsWith(String,Start)
|
||||
String = String:upper()
|
||||
Start = Start:upper()
|
||||
return string.sub(String,1,string.len(Start))==Start
|
||||
end
|
||||
|
||||
function complete(input)
|
||||
local allCompletions = {"Hello", "World", "Foo", "Bar"}
|
||||
local result = {}
|
||||
|
||||
for i,v in pairs(allCompletions) do
|
||||
if StartsWith(v, input) then
|
||||
table.insert(result, v)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function foo(arg)
|
||||
messenger:Message(arg)
|
||||
end
|
||||
|
||||
MakeCommand("foo", "example.foo", MakeCompletion("example.complete"))
|
||||
```
|
||||
for all runtime files. In addition, there is `AddRuntimeFileFromMemory` which
|
||||
adds a runtime file based on a string that may have been constructed at
|
||||
runtime.
|
||||
|
||||
## Default plugins
|
||||
|
||||
For examples of plugins, see the default `autoclose` and `linter` plugins
|
||||
(stored in the normal micro core repo under `runtime/plugins`) as well as any
|
||||
plugins that are stored in the official channel
|
||||
[here](https://github.com/micro-editor/plugin-channel).
|
||||
There are 6 default plugins that come pre-installed with micro. These are
|
||||
|
||||
* `autoclose`: automatically closes brackets, quotes, etc...
|
||||
* `comment`: provides automatic commenting for a number of languages
|
||||
* `ftoptions`: alters some default options depending on the filetype
|
||||
* `linter`: provides extensible linting for many languages
|
||||
* `literate`: provides advanced syntax highlighting for the Literate
|
||||
programming tool.
|
||||
* `status`: provides some extensions to the status line (integration with
|
||||
Git and more).
|
||||
|
||||
These are good examples for many use-cases if you are looking to write
|
||||
your own plugins.
|
||||
|
||||
## Plugin Manager
|
||||
|
||||
Micro also has a built in plugin manager which you can invoke with the
|
||||
`> plugin ...` command.
|
||||
|
||||
For the valid commands you can use, see the `commands` help topic.
|
||||
|
||||
The manager fetches plugins from the channels (which is simply a list of plugin
|
||||
metadata) which it knows about. By default, micro only knows about the official
|
||||
channel which is located at github.com/micro-editor/plugin-channel but you can
|
||||
add your own third-party channels using the `pluginchannels` option and you can
|
||||
directly link third-party plugins to allow installation through the plugin
|
||||
manager with the `pluginrepos` option.
|
||||
|
||||
If you'd like to publish a plugin you've made as an official plugin, you should
|
||||
upload your plugin online (to Github preferably) and add a `repo.json` file.
|
||||
This file will contain the metadata for your plugin. Here is an example:
|
||||
|
||||
```json
|
||||
[{
|
||||
"Name": "pluginname",
|
||||
"Description": "Here is a nice concise description of my plugin",
|
||||
"Tags": ["python", "linting"],
|
||||
"Versions": [
|
||||
{
|
||||
"Version": "1.0.0",
|
||||
"Url": "https://github.com/user/plugin/archive/v1.0.0.zip",
|
||||
"Require": {
|
||||
"micro": ">=1.0.3"
|
||||
}
|
||||
}
|
||||
]
|
||||
}]
|
||||
```
|
||||
|
||||
Then open a pull request at github.com/micro-editor/plugin-channel adding a link
|
||||
to the raw `repo.json` that is in your plugin repository. To make updating the
|
||||
plugin work, the first line of your plugins lua code should contain the version
|
||||
of the plugin. (Like this: `VERSION = "1.0.0"`) Please make sure to use
|
||||
[semver](http://semver.org/) for versioning.
|
||||
Micro's plugin manager is you! Ultimately the plugins that are created
|
||||
for micro are quite simple and don't require a complex automated tool
|
||||
to manage them. They should be "git cloned" or somehow placed in the
|
||||
`~/.config/micro/plug` directory, and that is all that's necessary
|
||||
for installation. In the rare case that a more complex installation
|
||||
process is needed (such as dependencies, or additional setup) the
|
||||
plugin creator should provide the additional instructions on their
|
||||
website and point to the link using the `install` field in the `info.json`
|
||||
file.
|
||||
|
||||
@@ -16,7 +16,7 @@ the settings and their values. To change an option, you can either change the
|
||||
value in the `settings.json` file, or you can type it in directly while using
|
||||
micro.
|
||||
|
||||
Simply press CtrlE to go to command mode, and type `set option value` (in the
|
||||
Press CtrlE to go to command mode, and type `set option value` (in the
|
||||
future, I will use `> set option value` to indicate pressing CtrlE). The change
|
||||
will take effect immediately and will also be saved to the `settings.json` file
|
||||
so that the setting will stick even after you close micro.
|
||||
@@ -70,31 +70,40 @@ what actions are available, see the `keybindings` help topic (`> help keybinding
|
||||
|
||||
If you need more power than the json files provide, you can use the `init.lua`
|
||||
file. Create it in `~/.config/micro`. This file is a lua file that is run when
|
||||
micro starts and is essentially a one-file plugin.
|
||||
micro starts and is essentially a one-file plugin. The plugin name is `initlua`.
|
||||
|
||||
I'll show you how to use the `init.lua` file by giving an example of how to
|
||||
create a binding to `CtrlR` which will execute `go run` on the current file,
|
||||
This example will show you how to use the `init.lua` file by creating
|
||||
a binding to `CtrlR` which will execute the bash command `go run` on the current file,
|
||||
given that the current file is a Go file.
|
||||
|
||||
You can do that by putting the following in `init.lua`:
|
||||
|
||||
```lua
|
||||
function gorun()
|
||||
local buf = CurView().Buf -- The current buffer
|
||||
if buf:FileType() == "go" then
|
||||
HandleShellCommand("go run " .. buf.Path, true, true) -- the first true means don't run it in the background
|
||||
end
|
||||
local config = import("micro/config")
|
||||
local shell = import("micro/shell")
|
||||
|
||||
function init()
|
||||
-- true means overwrite any existing binding to CtrlR
|
||||
-- this will modify the bindings.json file
|
||||
config.TryBindKey("CtrlR", "lua:initlua.gorun", true)
|
||||
end
|
||||
|
||||
BindKey("CtrlR", "init.gorun")
|
||||
function gorun(bp)
|
||||
local buf = bp.Buf
|
||||
if buf:FileType() == "go" then
|
||||
-- the true means run in the foreground
|
||||
-- the false means send output to stdout (instead of returning it)
|
||||
shell.RunInteractiveShell("go run " .. buf.Path, true, false)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Alternatively, you could get rid of the `BindKey` line, and put this line in the
|
||||
Alternatively, you could get rid of the `TryBindKey` line, and put this line in the
|
||||
`bindings.json` file:
|
||||
|
||||
```json
|
||||
{
|
||||
"CtrlR": "init.gorun"
|
||||
"CtrlR": "lua:initlua.gorun"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
40
runtime/plugins/status/status.lua
Normal file
40
runtime/plugins/status/status.lua
Normal file
@@ -0,0 +1,40 @@
|
||||
micro = import("micro")
|
||||
buffer = import("micro/buffer")
|
||||
config = import("micro/config")
|
||||
|
||||
function init()
|
||||
micro.SetStatusInfoFn("status.branch")
|
||||
micro.SetStatusInfoFn("status.hash")
|
||||
micro.SetStatusInfoFn("status.paste")
|
||||
end
|
||||
|
||||
function branch(b)
|
||||
if b.Type.Kind ~= buffer.BTInfo then
|
||||
local shell = import("micro/shell")
|
||||
local strings = import("strings")
|
||||
|
||||
local branch, err = shell.ExecCommand("git", "rev-parse", "--abbrev-ref", "HEAD")
|
||||
if err == nil then
|
||||
return strings.TrimSpace(branch)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function hash(b)
|
||||
if b.Type.Kind ~= 5 then
|
||||
local shell = import("micro/shell")
|
||||
local strings = import("strings")
|
||||
|
||||
local hash, err = shell.ExecCommand("git", "rev-parse", "--short", "HEAD")
|
||||
if err == nil then
|
||||
return strings.TrimSpace(hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function paste(b)
|
||||
if config.GetGlobalOption("paste") then
|
||||
return "PASTE "
|
||||
end
|
||||
return ""
|
||||
end
|
||||
@@ -5,9 +5,9 @@ detect:
|
||||
|
||||
rules:
|
||||
# Conditionals and control flow
|
||||
- special: "\\b(break|case|continue|default|go|goto|range|return)\\b"
|
||||
- statement: "\\b(else|for|if|switch)\\b"
|
||||
- preproc: "\\b(package|import|const|var|type|struct|func|go|defer|iota)\\b"
|
||||
- special: "\\b(break|case|continue|default|go|goto|range|return|println|fallthrough)\\b"
|
||||
- statement: "\\b(else|for|if|switch|select)\\b"
|
||||
- preproc: "\\b(package|import|const|var|type|struct|func|defer|iota|make|new|copy|len|cap|panic|append|close|delete|print|recover)\\b"
|
||||
- symbol.operator: "[-+/*=<>!~%&|^]|:="
|
||||
|
||||
# Types
|
||||
|
||||
@@ -13,7 +13,7 @@ rules:
|
||||
# definitions
|
||||
- identifier: "[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[(]"
|
||||
# keywords
|
||||
- statement: "\\b(begin|break|catch|continue|function|elseif|struct|else|end|finally|for|global|local|let|const|if|import|using|macro|println|return|try|while|module)\\b"
|
||||
- statement: "\\b(begin|break|catch|continue|function|elseif|struct|else|end|finally|for|global|local|let|const|if|import|export|using|macro|println|return|try|while|module)\\b"
|
||||
# decorators
|
||||
- identifier.macro: "@[A-Za-z0-9_]+"
|
||||
# operators
|
||||
|
||||
@@ -9,7 +9,12 @@ rules:
|
||||
start: "<!DOCTYPE"
|
||||
end: "[/]?>"
|
||||
rules: []
|
||||
- comment: "<!--.+?-->"
|
||||
|
||||
- comment:
|
||||
start: "<!--"
|
||||
end: "-->"
|
||||
rules: []
|
||||
|
||||
- symbol.tag:
|
||||
start: "<\\??"
|
||||
end: "\\??>"
|
||||
|
||||
@@ -15,7 +15,7 @@ rules:
|
||||
# Numbers (hexadecimal + decimal)
|
||||
- constant.number: "\\b(0x[A-F0-9]+|[0-9]+)\\b"
|
||||
# Primitive Types / Derived Data Types
|
||||
- type: "([A-Z][a-z]+|(i8|u8|i16|u16|i32|u32|i64|u64|i128|u128|isize|usize|c_short|c_ushort|c_int|c_uint|c_long|c_ulong|c_longlong|c_ulonglong|c_longdouble|c_void|f16|f32|f64|f128|bool|void|noreturn|type|anyerror|comptime_int|comptime_float))"
|
||||
- type: "\\b([A-Z][a-z]+|(i8|u8|i16|u16|i32|u32|i64|u64|i128|u128|isize|usize|c_short|c_ushort|c_int|c_uint|c_long|c_ulong|c_longlong|c_ulonglong|c_longdouble|c_void|f16|f32|f64|f128|bool|void|noreturn|type|anyerror|comptime_int|comptime_float))\\b"
|
||||
|
||||
- constant.string:
|
||||
start: "\""
|
||||
|
||||
Reference in New Issue
Block a user