Compare commits

..

2 Commits

Author SHA1 Message Date
Zachary Yedidia
bc974e13f0 Cross compile binaries in release scripts 2020-02-16 00:40:51 +00:00
Zachary Yedidia
11534a2aeb Use hub for creating releases 2020-02-15 19:33:49 -05:00
90 changed files with 1281 additions and 5035 deletions

View File

@@ -2,7 +2,7 @@
## Specifications
<!-- You can use `micro -version` to get the commit hash. -->
You can use `micro -version` to get the commit hash.
Commit hash:
OS:

2
.gitignore vendored
View File

@@ -11,10 +11,8 @@ todo.txt
test.txt
log.txt
*.old
benchmark_results*
tools/build-version
tools/build-date
tools/info-plist
tools/bindata
tools/vscode-tests/
*.hdr

View File

@@ -8,16 +8,14 @@ DATE = $(shell GOOS=$(shell go env GOHOSTOS) GOARCH=$(shell go env GOHOSTARCH) \
ADDITIONAL_GO_LINKER_FLAGS = $(shell GOOS=$(shell go env GOHOSTOS) \
GOARCH=$(shell go env GOHOSTARCH))
GOBIN ?= $(shell go env GOPATH)/bin
GOVARS = -X github.com/zyedidia/micro/v2/internal/util.Version=$(VERSION) -X github.com/zyedidia/micro/v2/internal/util.CommitHash=$(HASH) -X 'github.com/zyedidia/micro/v2/internal/util.CompileDate=$(DATE)'
DEBUGVAR = -X github.com/zyedidia/micro/v2/internal/util.Debug=ON
VSCODE_TESTS_BASE_URL = 'https://raw.githubusercontent.com/microsoft/vscode/e6a45f4242ebddb7aa9a229f85555e8a3bd987e2/src/vs/editor/test/common/model/'
GOVARS = -X github.com/zyedidia/micro/internal/util.Version=$(VERSION) -X github.com/zyedidia/micro/internal/util.CommitHash=$(HASH) -X 'github.com/zyedidia/micro/internal/util.CompileDate=$(DATE)' -X github.com/zyedidia/micro/internal/util.Debug=OFF
# Builds micro after checking dependencies but without updating the runtime
build:
go build -ldflags "-s -w $(GOVARS) $(ADDITIONAL_GO_LINKER_FLAGS)" ./cmd/micro
build-dbg:
go build -ldflags "-s -w $(ADDITIONAL_GO_LINKER_FLAGS) $(DEBUGVAR)" ./cmd/micro
go build -ldflags "-s -w $(ADDITIONAL_GO_LINKER_FLAGS)" ./cmd/micro
build-tags: fetch-tags
go build -ldflags "-s -w $(GOVARS) $(ADDITIONAL_GO_LINKER_FLAGS)" ./cmd/micro
@@ -52,34 +50,8 @@ runtime:
mv runtime.go internal/config
gofmt -w internal/config/runtime.go
testgen:
mkdir -p tools/vscode-tests
cd tools/vscode-tests && \
curl --remote-name-all $(VSCODE_TESTS_BASE_URL){editableTextModelAuto,editableTextModel,model.line}.test.ts
tsc tools/vscode-tests/*.ts > /dev/null; true
go run tools/testgen.go tools/vscode-tests/*.js > buffer_generated_test.go
mv buffer_generated_test.go internal/buffer
gofmt -w internal/buffer/buffer_generated_test.go
test:
go test ./internal/...
bench:
for i in 1 2 3; do \
go test -bench=. ./internal/...; \
done > benchmark_results
benchstat benchmark_results
bench-baseline:
for i in 1 2 3; do \
go test -bench=. ./internal/...; \
done > benchmark_results_baseline
bench-compare:
for i in 1 2 3; do \
go test -bench=. ./internal/...; \
done > benchmark_results
benchstat benchmark_results_baseline benchmark_results
clean:
rm -f micro

View File

@@ -56,10 +56,10 @@ You can also check out the website for Micro at https://micro-editor.github.io.
- 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 plugins.
- Built-in diff gutter.
- Simple autocompletion.
- Built-in diff gutter
- Simple autocompletion
- Persistent undo.
- Automatic linting and error notifications.
- Automatic linting and error notifications
- Syntax highlighting for over [130 languages](runtime/syntax).
- Color scheme support.
- By default, micro comes with 16, 256, and true color themes.
@@ -76,26 +76,28 @@ To install micro, you can download a [prebuilt binary](https://github.com/zyedid
If you want more information about ways to install micro, see this [wiki page](https://github.com/zyedidia/micro/wiki/Installing-Micro).
Use `micro -version` to get the version information after installing. It is only guaranteed that you are installing the most recent
stable version if you install from the prebuilt binaries, Homebrew, or Snap.
### Prebuilt binaries
All you need to install micro is one file, the binary itself. It's as simple as that!
Download the binary from the [releases](https://github.com/zyedidia/micro/releases) page.
On that page you'll see the nightly release, which contains binaries for micro which are built every night,
and you'll see all the stable releases with the corresponding binaries.
Running `micro -version` will give you the version information.
### Installation script
There is a script which can install micro for you by downloading the latest prebuilt binary. You can find it at <https://getmic.ro>.
You can easily install micro by running
Then you can easily install micro:
```bash
curl https://getmic.ro | bash
```
The script will place the micro binary in the current directory. See its [GitHub repository](https://github.com/benweissmann/getmic.ro) for more information.
The script will install the micro binary to the current directory. See its [GitHub repository](https://github.com/benweissmann/getmic.ro) for more information.
### Package managers
@@ -105,35 +107,27 @@ You can install micro using Homebrew on Mac:
brew install micro
```
**Note for Mac:** All micro keybindings use the control or alt (option) key, not the command
key. By default, macOS terminals do not forward alt key events. To fix this, please see
the section on [macOS terminals](https://github.com/zyedidia/micro#macos-terminal) further below.
On Linux, you can install micro through [snap](https://snapcraft.io/docs/core/install)
```
snap install micro --classic
```
**Note for Linux:** for interfacing with the local system clipboard, `xclip` or `xsel`
must be installed. Please see the section on [Linux clipboard support](https://github.com/zyedidia/micro#linux-clipboard-support)
further below.
On Debian `unstable | testing | buster-backports` and Ubuntu `focal` (20.04), micro is available
via `apt`:
Micro is also available through other package managers on Linux such as apt, dnf, AUR, Nix, and package managers
for other operating systems. These packages are not guaranteed to be up-to-date.
```
sudo apt install micro
```
* Linux: Available in distro-specific package managers.
* `apt install micro` (Ubuntu 20.04 `focal`, and Debian `unstable | testing | buster-backports`).
* `dnf install micro` (Fedora).
* `yay -S micro` (Arch Linux).
* See [wiki](https://github.com/zyedidia/micro/wiki/Installing-Micro) for details about CRUX, Termux.
* 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`.
* NetBSD, macOS, Linux, Illumos, etc. with [pkgsrc](http://www.pkgsrc.org/)-current:
* `pkg_add 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
@@ -249,5 +243,3 @@ You can use the [GitHub issue tracker](https://github.com/zyedidia/micro/issues)
to report bugs, ask questions, or suggest new features.
For a more informal setting to discuss the editor, you can join the [Gitter chat](https://gitter.im/zyedidia/micro).
Sometimes I am unresponsive, and I apologize! If that happens, please ping me.

View File

@@ -10,8 +10,8 @@ import (
"sort"
"strings"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/internal/buffer"
"github.com/zyedidia/micro/internal/config"
)
func shouldContinue() bool {

View File

@@ -4,7 +4,7 @@ import (
"log"
"os"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/util"
)
// NullWriter simply sends writes into the void

View File

@@ -6,14 +6,14 @@ import (
lua "github.com/yuin/gopher-lua"
luar "layeh.com/gopher-luar"
"github.com/zyedidia/micro/v2/internal/action"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/display"
ulua "github.com/zyedidia/micro/v2/internal/lua"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/shell"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/action"
"github.com/zyedidia/micro/internal/buffer"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/display"
ulua "github.com/zyedidia/micro/internal/lua"
"github.com/zyedidia/micro/internal/screen"
"github.com/zyedidia/micro/internal/shell"
"github.com/zyedidia/micro/internal/util"
)
func init() {
@@ -53,9 +53,6 @@ func luaImportMicro() *lua.LTable {
ulua.L.SetField(pkg, "CurTab", luar.New(ulua.L, func() *action.Tab {
return action.MainTab()
}))
ulua.L.SetField(pkg, "Tabs", luar.New(ulua.L, func() *action.TabList {
return action.Tabs
}))
return pkg
}
@@ -86,7 +83,6 @@ func luaImportMicroConfig() *lua.LTable {
ulua.L.SetField(pkg, "GetGlobalOption", luar.New(ulua.L, config.GetGlobalOption))
ulua.L.SetField(pkg, "SetGlobalOption", luar.New(ulua.L, action.SetGlobalOption))
ulua.L.SetField(pkg, "SetGlobalOptionNative", luar.New(ulua.L, action.SetGlobalOptionNative))
ulua.L.SetField(pkg, "ConfigDir", luar.New(ulua.L, config.ConfigDir))
return pkg
}
@@ -145,7 +141,6 @@ func luaImportMicroUtil() *lua.LTable {
ulua.L.SetField(pkg, "GetLeadingWhitespace", luar.New(ulua.L, util.LuaGetLeadingWhitespace))
ulua.L.SetField(pkg, "IsWordChar", luar.New(ulua.L, util.LuaIsWordChar))
ulua.L.SetField(pkg, "String", luar.New(ulua.L, util.String))
ulua.L.SetField(pkg, "CharacterCountInString", luar.New(ulua.L, util.CharacterCountInString))
ulua.L.SetField(pkg, "RuneStr", luar.New(ulua.L, func(r rune) string {
return string(r)
}))

View File

@@ -5,21 +5,19 @@ import (
"fmt"
"io/ioutil"
"os"
"regexp"
"runtime"
"sort"
"strconv"
"time"
"github.com/go-errors/errors"
isatty "github.com/mattn/go-isatty"
lua "github.com/yuin/gopher-lua"
"github.com/zyedidia/micro/v2/internal/action"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/shell"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/action"
"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/tcell"
)
@@ -45,8 +43,7 @@ func InitFlags() {
fmt.Println(" \tCleans the configuration directory")
fmt.Println("-config-dir dir")
fmt.Println(" \tSpecify a custom location for the configuration directory")
fmt.Println("[FILE]:LINE:COL (if the `parsecursor` option is enabled)")
fmt.Println("+LINE:COL")
fmt.Println("[FILE]:LINE:COL")
fmt.Println(" \tSpecify a line and column to start the cursor at when opening a buffer")
fmt.Println("-options")
fmt.Println(" \tShow all option help")
@@ -150,45 +147,11 @@ func LoadInput() []*buffer.Buffer {
args := flag.Args()
buffers := make([]*buffer.Buffer, 0, len(args))
btype := buffer.BTDefault
if !isatty.IsTerminal(os.Stdout.Fd()) {
btype = buffer.BTStdout
}
files := make([]string, 0, len(args))
flagStartPos := buffer.Loc{-1, -1}
flagr := regexp.MustCompile(`^\+(\d+)(?::(\d+))?$`)
for _, a := range args {
match := flagr.FindStringSubmatch(a)
if len(match) == 3 && match[2] != "" {
line, err := strconv.Atoi(match[1])
if err != nil {
screen.TermMessage(err)
continue
}
col, err := strconv.Atoi(match[2])
if err != nil {
screen.TermMessage(err)
continue
}
flagStartPos = buffer.Loc{col - 1, line - 1}
} else if len(match) == 3 && match[2] == "" {
line, err := strconv.Atoi(match[1])
if err != nil {
screen.TermMessage(err)
continue
}
flagStartPos = buffer.Loc{0, line - 1}
} else {
files = append(files, a)
}
}
if len(files) > 0 {
if len(args) > 0 {
// Option 1
// We go through each file and load it
for i := 0; i < len(files); i++ {
buf, err := buffer.NewBufferFromFileAtLoc(files[i], btype, flagStartPos)
for i := 0; i < len(args); i++ {
buf, err := buffer.NewBufferFromFile(args[i], buffer.BTDefault)
if err != nil {
screen.TermMessage(err)
continue
@@ -205,22 +168,17 @@ func LoadInput() []*buffer.Buffer {
screen.TermMessage("Error reading from stdin: ", err)
input = []byte{}
}
buffers = append(buffers, buffer.NewBufferFromStringAtLoc(string(input), filename, btype, flagStartPos))
buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, buffer.BTDefault))
} else {
// Option 3, just open an empty buffer
buffers = append(buffers, buffer.NewBufferFromStringAtLoc(string(input), filename, btype, flagStartPos))
buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, buffer.BTDefault))
}
return buffers
}
func main() {
defer func() {
if util.Stdout.Len() > 0 {
fmt.Fprint(os.Stdout, util.Stdout.String())
}
os.Exit(0)
}()
defer os.Exit(0)
// runtime.SetCPUProfileRate(400)
// f, _ := os.Create("micro.prof")
@@ -243,10 +201,7 @@ func main() {
if err != nil {
screen.TermMessage(err)
}
err = config.InitGlobalSettings()
if err != nil {
screen.TermMessage(err)
}
config.InitGlobalSettings()
// flag options
for k, v := range optionFlags {
@@ -380,9 +335,6 @@ func DoEvent() {
case <-shell.CloseTerms:
case event = <-events:
case <-screen.DrawChan():
for len(screen.DrawChan()) > 0 {
<-screen.DrawChan()
}
}
if action.InfoBar.HasPrompt {

8
go.mod
View File

@@ -1,4 +1,4 @@
module github.com/zyedidia/micro/v2
module github.com/zyedidia/micro
require (
github.com/blang/semver v3.5.1+incompatible
@@ -8,19 +8,17 @@ require (
github.com/mattn/go-isatty v0.0.11
github.com/mattn/go-runewidth v0.0.7
github.com/mitchellh/go-homedir v1.1.0
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff
github.com/sergi/go-diff v1.1.0
github.com/stretchr/testify v1.4.0
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb
github.com/zyedidia/clipboard v0.0.0-20200421031010-7c45b8673834
github.com/zyedidia/clipboard v0.0.0-20190823154308-241f98e9b197
github.com/zyedidia/glob v0.0.0-20170209203856-dd4023a66dc3
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.6
github.com/zyedidia/tcell v1.4.4
github.com/zyedidia/terminal v0.0.0-20180726154117-533c623e2415
golang.org/x/text v0.3.2
gopkg.in/sourcemap.v1 v1.0.5 // indirect
gopkg.in/yaml.v2 v2.2.7
layeh.com/gopher-luar v1.0.7
)

12
go.sum
View File

@@ -29,8 +29,6 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff h1:+6NUiITWwE5q1KO6SAfUX918c+Tab0+tGAM/mtdlUyA=
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
@@ -42,8 +40,6 @@ github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
github.com/zyedidia/clipboard v0.0.0-20190823154308-241f98e9b197 h1:gYTNnAW6azuB3BbA6QYWO/H4F2ABSOjjw3Z03tlXd2c=
github.com/zyedidia/clipboard v0.0.0-20190823154308-241f98e9b197/go.mod h1:WDk3p8GiZV9+xFWlSo8qreeoLhW6Ik692rqXk+cNeRY=
github.com/zyedidia/clipboard v0.0.0-20200421031010-7c45b8673834 h1:0nOfq3JwYRiY3+nwfWVQYEaXDmGCQgj3RKoqTifLzP4=
github.com/zyedidia/clipboard v0.0.0-20200421031010-7c45b8673834/go.mod h1:zykFnZUXX0ErxqvYLUFEq7QDJKId8rmh2FgD0/Y8cjA=
github.com/zyedidia/glob v0.0.0-20170209203856-dd4023a66dc3 h1:oMHjjTLfGXVuyOQBYj5/td9WC0mw4g1xDBPovIqmHew=
github.com/zyedidia/glob v0.0.0-20170209203856-dd4023a66dc3/go.mod h1:YKbIYP//Eln8eDgAJGI3IDvR3s4Tv9Z9TGIOumiyQ5c=
github.com/zyedidia/highlight v0.0.0-20170330143449-201131ce5cf5 h1:Zs6mpwXvlqpF9zHl5XaN0p5V4J9XvP+WBuiuXyIgqvc=
@@ -54,12 +50,10 @@ github.com/zyedidia/poller v1.0.1 h1:Tt9S3AxAjXwWGNiC2TUdRJkQDZSzCBNVQ4xXiQ7440s
github.com/zyedidia/poller v1.0.1/go.mod h1:vZXJOHGDcuK08GXhF6IAY0ZFd2WcgOR5DOTp84Uk5eE=
github.com/zyedidia/pty v2.0.0+incompatible h1:Ou5vXL6tvjst+RV8sUFISbuKDnUJPhnpygApMFGweqw=
github.com/zyedidia/pty v2.0.0+incompatible/go.mod h1:4y9l9yJZNxRa7GB/fB+mmDmGkG3CqmzLf4vUxGGotEA=
github.com/zyedidia/tcell v1.4.3 h1:s0nmxj22Jj+vyt4nVmnB6kbnwRxEay1zfS0j8IsbtfI=
github.com/zyedidia/tcell v1.4.3/go.mod h1:HhlbMSCcGX15rFDB+Q1Lk3pKEOocsCUAQC3zhZ9sadA=
github.com/zyedidia/tcell v1.4.4 h1:o34LXujNuSueuyTy+5eoQW+rQr8g0UbY8k1NczZyskQ=
github.com/zyedidia/tcell v1.4.4/go.mod h1:HhlbMSCcGX15rFDB+Q1Lk3pKEOocsCUAQC3zhZ9sadA=
github.com/zyedidia/tcell v1.4.5 h1:JFmOiWLxr3Fsk2vjRL3n8oRUoJeyrazGhkhZqW31kEY=
github.com/zyedidia/tcell v1.4.5/go.mod h1:HhlbMSCcGX15rFDB+Q1Lk3pKEOocsCUAQC3zhZ9sadA=
github.com/zyedidia/tcell v1.4.6 h1:8OYvZpUyqYQ3nigenBwOtnY3fXWEHekbm6QYchBeOxs=
github.com/zyedidia/tcell v1.4.6/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=
@@ -73,8 +67,6 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=

View File

@@ -5,14 +5,15 @@ import (
"runtime"
"strings"
"time"
"unicode/utf8"
shellquote "github.com/kballard/go-shellquote"
"github.com/zyedidia/clipboard"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/shell"
"github.com/zyedidia/micro/v2/internal/util"
"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/tcell"
)
@@ -174,7 +175,7 @@ func (h *BufPane) CursorRight() bool {
if tabstospaces && tabmovement {
tabsize := int(h.Buf.Settings["tabsize"].(float64))
line := h.Buf.LineBytes(h.Cursor.Y)
if h.Cursor.X+tabsize < util.CharacterCount(line) && util.IsSpaces(line[h.Cursor.X:h.Cursor.X+tabsize]) && util.IsBytesWhitespace(line[0:h.Cursor.X]) {
if h.Cursor.X+tabsize < utf8.RuneCount(line) && util.IsSpaces(line[h.Cursor.X:h.Cursor.X+tabsize]) && util.IsBytesWhitespace(line[0:h.Cursor.X]) {
for i := 0; i < tabsize; i++ {
h.Cursor.Right()
}
@@ -290,19 +291,6 @@ func (h *BufPane) StartOfText() bool {
return true
}
// StartOfTextToggle toggles the cursor between the start of the text of the line
// and the start of the line
func (h *BufPane) StartOfTextToggle() bool {
h.Cursor.Deselect(true)
if h.Cursor.IsStartOfText() {
h.Cursor.Start()
} else {
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)
@@ -337,22 +325,6 @@ func (h *BufPane) SelectToStartOfText() bool {
return true
}
// SelectToStartOfTextToggle toggles the selection between the start of the text
// on the current line and the start of the line
func (h *BufPane) SelectToStartOfTextToggle() bool {
if !h.Cursor.HasSelection() {
h.Cursor.OrigSelection[0] = h.Cursor.Loc
}
if h.Cursor.IsStartOfText() {
h.Cursor.Start()
} else {
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() {
@@ -485,7 +457,7 @@ func (h *BufPane) InsertNewline() bool {
// Remove the whitespaces if keepautoindent setting is off
if util.IsSpacesOrTabs(h.Buf.LineBytes(h.Cursor.Y-1)) && !h.Buf.Settings["keepautoindent"].(bool) {
line := h.Buf.LineBytes(h.Cursor.Y - 1)
h.Buf.Remove(buffer.Loc{X: 0, Y: h.Cursor.Y - 1}, buffer.Loc{X: util.CharacterCount(line), Y: h.Cursor.Y - 1})
h.Buf.Remove(buffer.Loc{X: 0, Y: h.Cursor.Y - 1}, buffer.Loc{X: utf8.RuneCount(line), Y: h.Cursor.Y - 1})
}
}
h.Cursor.LastVisualX = h.Cursor.GetVisualX()
@@ -510,7 +482,7 @@ func (h *BufPane) Backspace() bool {
// tab (tabSize number of spaces)
lineStart := util.SliceStart(h.Buf.LineBytes(h.Cursor.Y), h.Cursor.X)
tabSize := int(h.Buf.Settings["tabsize"].(float64))
if h.Buf.Settings["tabstospaces"].(bool) && util.IsSpaces(lineStart) && len(lineStart) != 0 && util.CharacterCount(lineStart)%tabSize == 0 {
if h.Buf.Settings["tabstospaces"].(bool) && util.IsSpaces(lineStart) && len(lineStart) != 0 && utf8.RuneCount(lineStart)%tabSize == 0 {
loc := h.Cursor.Loc
h.Buf.Remove(loc.Move(-tabSize, h.Buf), loc)
} else {
@@ -663,12 +635,7 @@ func (h *BufPane) Autocomplete() bool {
return false
}
if h.Cursor.X == 0 {
return false
}
r := h.Cursor.RuneUnder(h.Cursor.X)
prev := h.Cursor.RuneUnder(h.Cursor.X - 1)
if !util.IsAutocomplete(prev) || !util.IsNonAlphaNumeric(r) {
if !util.IsNonAlphaNumeric(h.Cursor.RuneUnder(h.Cursor.X)) {
// don't autocomplete if cursor is on alpha numeric character (middle of a word)
return false
}
@@ -732,7 +699,6 @@ func (h *BufPane) Save() bool {
}
// SaveAsCB performs a save as and does a callback at the very end (after all prompts have been resolved)
// The callback is only called if the save was successful
func (h *BufPane) SaveAsCB(action string, callback func()) bool {
InfoBar.Prompt("Filename: ", "", "Save", nil, func(resp string, canceled bool) {
if !canceled {
@@ -763,7 +729,6 @@ 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
// The callback is only called if the save was successful
func (h *BufPane) saveBufToFile(filename string, action string, callback func()) bool {
err := h.Buf.SaveAs(filename)
if err != nil {
@@ -776,9 +741,6 @@ func (h *BufPane) saveBufToFile(filename string, action string, callback func())
h.Buf.Path = filename
h.Buf.SetName(filename)
InfoBar.Message("Saved " + filename)
if callback != nil {
callback()
}
}
}
if h.Buf.Settings["autosu"].(bool) {
@@ -789,6 +751,9 @@ func (h *BufPane) saveBufToFile(filename string, action string, callback func())
saveWithSudo()
h.completeAction(action)
}
if callback != nil {
callback()
}
})
return false
}
@@ -799,32 +764,19 @@ func (h *BufPane) saveBufToFile(filename string, action string, callback func())
h.Buf.Path = filename
h.Buf.SetName(filename)
InfoBar.Message("Saved " + filename)
if callback != nil {
callback()
}
}
if callback != nil {
callback()
}
return true
}
// Find opens a prompt and searches forward for the input
func (h *BufPane) Find() bool {
return h.find(true)
}
// FindLiteral is the same as Find() but does not support regular expressions
func (h *BufPane) FindLiteral() bool {
return h.find(false)
}
func (h *BufPane) find(useRegex bool) bool {
h.searchOrig = h.Cursor.Loc
prompt := "Find: "
if useRegex {
prompt = "Find (regex): "
}
InfoBar.Prompt(prompt, "", "Find", func(resp string) {
InfoBar.Prompt("Find: ", "", "Find", func(resp string) {
// Event callback
match, found, _ := h.Buf.FindNext(resp, h.Buf.Start(), h.Buf.End(), h.searchOrig, true, useRegex)
match, found, _ := h.Buf.FindNext(resp, h.Buf.Start(), h.Buf.End(), h.searchOrig, true, true)
if found {
h.Cursor.SetSelectionStart(match[0])
h.Cursor.SetSelectionEnd(match[1])
@@ -839,7 +791,7 @@ func (h *BufPane) find(useRegex bool) bool {
}, func(resp string, canceled bool) {
// Finished callback
if !canceled {
match, found, err := h.Buf.FindNext(resp, h.Buf.Start(), h.Buf.End(), h.searchOrig, true, useRegex)
match, found, err := h.Buf.FindNext(resp, h.Buf.Start(), h.Buf.End(), h.searchOrig, true, true)
if err != nil {
InfoBar.Error(err)
}
@@ -850,7 +802,6 @@ func (h *BufPane) find(useRegex bool) bool {
h.Cursor.OrigSelection[1] = h.Cursor.CurSelection[1]
h.Cursor.GotoLoc(h.Cursor.CurSelection[1])
h.lastSearch = resp
h.lastSearchRegex = useRegex
} else {
h.Cursor.ResetSelection()
InfoBar.Message("No matches found")
@@ -874,7 +825,7 @@ func (h *BufPane) FindNext() bool {
if h.Cursor.HasSelection() {
searchLoc = h.Cursor.CurSelection[1]
}
match, found, err := h.Buf.FindNext(h.lastSearch, h.Buf.Start(), h.Buf.End(), searchLoc, true, h.lastSearchRegex)
match, found, err := h.Buf.FindNext(h.lastSearch, h.Buf.Start(), h.Buf.End(), searchLoc, true, true)
if err != nil {
InfoBar.Error(err)
}
@@ -901,7 +852,7 @@ func (h *BufPane) FindPrevious() bool {
if h.Cursor.HasSelection() {
searchLoc = h.Cursor.CurSelection[0]
}
match, found, err := h.Buf.FindNext(h.lastSearch, h.Buf.Start(), h.Buf.End(), searchLoc, false, h.lastSearchRegex)
match, found, err := h.Buf.FindNext(h.lastSearch, h.Buf.Start(), h.Buf.End(), searchLoc, false, true)
if err != nil {
InfoBar.Error(err)
}
@@ -949,25 +900,6 @@ func (h *BufPane) Copy() bool {
return true
}
// Copy the current line to the clipboard
func (h *BufPane) CopyLine() bool {
if h.Cursor.HasSelection() {
return false
} else {
h.Cursor.SelectLine()
h.Cursor.CopySelection("clipboard")
h.freshClip = true
if clipboard.Unsupported {
InfoBar.Message("Copied line (install xclip for external clipboard)")
} else {
InfoBar.Message("Copied line")
}
}
h.Cursor.Deselect(true)
h.Relocate()
return true
}
// CutLine cuts the current line to the clipboard
func (h *BufPane) CutLine() bool {
h.Cursor.SelectLine()
@@ -1047,26 +979,15 @@ func (h *BufPane) MoveLinesUp() bool {
}
start := h.Cursor.CurSelection[0].Y
end := h.Cursor.CurSelection[1].Y
sel := 1
if start > end {
end, start = start, end
sel = 0
}
compensate := false
if h.Cursor.CurSelection[sel].X != 0 {
end++
} else {
compensate = true
}
h.Buf.MoveLinesUp(
start,
end,
)
if compensate {
h.Cursor.CurSelection[sel].Y -= 1
}
h.Cursor.CurSelection[1].Y -= 1
} else {
if h.Cursor.Loc.Y == 0 {
InfoBar.Message("Cannot move further up")
@@ -1091,14 +1012,8 @@ func (h *BufPane) MoveLinesDown() bool {
}
start := h.Cursor.CurSelection[0].Y
end := h.Cursor.CurSelection[1].Y
sel := 1
if start > end {
end, start = start, end
sel = 0
}
if h.Cursor.CurSelection[sel].X != 0 {
end++
}
h.Buf.MoveLinesDown(
@@ -1205,16 +1120,6 @@ func (h *BufPane) OpenFile() bool {
return true
}
// OpenFile opens a new file in the buffer
func (h *BufPane) JumpLine() bool {
InfoBar.Prompt("> ", "goto ", "Command", nil, func(resp string, canceled bool) {
if !canceled {
h.HandleCommand(resp)
}
})
return true
}
// Start moves the viewport to the start of the buffer
func (h *BufPane) Start() bool {
v := h.GetView()
@@ -1502,9 +1407,8 @@ func (h *BufPane) AddTab() bool {
// PreviousTab switches to the previous tab in the tab list
func (h *BufPane) PreviousTab() bool {
tabsLen := len(Tabs.List)
a := Tabs.Active() + tabsLen
Tabs.SetActive((a - 1) % tabsLen)
a := Tabs.Active()
Tabs.SetActive(util.Clamp(a-1, 0, len(Tabs.List)-1))
return true
}
@@ -1512,8 +1416,7 @@ func (h *BufPane) PreviousTab() bool {
// NextTab switches to the next tab in the tab list
func (h *BufPane) NextTab() bool {
a := Tabs.Active()
Tabs.SetActive((a + 1) % len(Tabs.List))
Tabs.SetActive(util.Clamp(a+1, 0, len(Tabs.List)-1))
return true
}

View File

@@ -5,7 +5,7 @@ package action
import (
"syscall"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/internal/screen"
)
// Suspend sends micro to the background. This is the same as pressing CtrlZ in most unix programs.

View File

@@ -10,8 +10,8 @@ import (
"unicode"
"github.com/zyedidia/json5"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/screen"
"github.com/zyedidia/tcell"
)
@@ -249,7 +249,6 @@ func UnbindKey(k string) error {
if a, ok := defaults[k]; ok {
BindKey(k, a)
} else if _, ok := config.Bindings[k]; ok {
BufUnmap(key)
delete(config.Bindings, k)
}

View File

@@ -7,11 +7,11 @@ import (
luar "layeh.com/gopher-luar"
lua "github.com/yuin/gopher-lua"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/display"
ulua "github.com/zyedidia/micro/v2/internal/lua"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/internal/buffer"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/display"
ulua "github.com/zyedidia/micro/internal/lua"
"github.com/zyedidia/micro/internal/screen"
"github.com/zyedidia/tcell"
)
@@ -103,7 +103,7 @@ func BufMapKey(k Event, action string) {
afn = f
names = append(names, a)
} else {
screen.TermMessage("Error in bindings: action", a, "does not exist")
screen.TermMessage("Error:", a, "does not exist")
continue
}
actionfns = append(actionfns, afn)
@@ -124,8 +124,6 @@ func BufMapKey(k Event, action string) {
break
}
}
// if the action changed the current pane, update the reference
h = MainTab().CurPane()
}
return true
}
@@ -141,17 +139,6 @@ func BufMapMouse(k MouseEvent, action string) {
}
}
// BufUnmap unmaps a key or mouse event from any action
func BufUnmap(k Event) {
delete(BufKeyBindings, k)
delete(BufKeyStrings, k)
switch e := k.(type) {
case MouseEvent:
delete(BufMouseBindings, e)
}
}
// The BufPane connects the buffer and the window
// It provides a cursor (or multiple) and defines a set of actions
// that can be taken on the buffer
@@ -192,8 +179,7 @@ type BufPane struct {
tripleClick bool
// Last search stores the last successful search for FindNext and FindPrev
lastSearch string
lastSearchRegex bool
lastSearch string
// Should the current multiple cursor selection search based on word or
// based on selection (false for selection, true for word)
multiWord bool
@@ -284,11 +270,7 @@ func (h *BufPane) SetID(i uint64) {
}
func (h *BufPane) Name() string {
n := h.Buf.GetName()
if h.Buf.Modified() {
n += " +"
}
return n
return h.Buf.GetName()
}
// HandleEvent executes the tcell event properly
@@ -332,7 +314,7 @@ func (h *BufPane) HandleEvent(event tcell.Event) {
switch e.Buttons() {
case tcell.Button1:
_, my := e.Position()
if h.Buf.Type.Kind != buffer.BTInfo.Kind && h.Buf.Settings["statusline"].(bool) && my >= h.GetView().Y+h.GetView().Height-1 {
if h.Buf.Settings["statusline"].(bool) && my >= h.GetView().Y+h.GetView().Height-1 {
cancel = true
}
case tcell.ButtonNone:
@@ -357,11 +339,10 @@ func (h *BufPane) HandleEvent(event tcell.Event) {
// release the mouse
// if !h.doubleClick && !h.tripleClick {
// h.Cursor.Loc = mouseLoc
// h.Cursor.SetSelectionEnd(h.Cursor.Loc)
// h.Cursor.CopySelection("primary")
// }
if h.Cursor.HasSelection() {
h.Cursor.CopySelection("primary")
}
h.mouseReleased = true
}
}
@@ -531,111 +512,106 @@ func (h *BufPane) SetActive(b bool) {
// BufKeyActions contains the list of all possible key actions the bufhandler could execute
var BufKeyActions = map[string]BufKeyAction{
"CursorUp": (*BufPane).CursorUp,
"CursorDown": (*BufPane).CursorDown,
"CursorPageUp": (*BufPane).CursorPageUp,
"CursorPageDown": (*BufPane).CursorPageDown,
"CursorLeft": (*BufPane).CursorLeft,
"CursorRight": (*BufPane).CursorRight,
"CursorStart": (*BufPane).CursorStart,
"CursorEnd": (*BufPane).CursorEnd,
"SelectToStart": (*BufPane).SelectToStart,
"SelectToEnd": (*BufPane).SelectToEnd,
"SelectUp": (*BufPane).SelectUp,
"SelectDown": (*BufPane).SelectDown,
"SelectLeft": (*BufPane).SelectLeft,
"SelectRight": (*BufPane).SelectRight,
"WordRight": (*BufPane).WordRight,
"WordLeft": (*BufPane).WordLeft,
"SelectWordRight": (*BufPane).SelectWordRight,
"SelectWordLeft": (*BufPane).SelectWordLeft,
"DeleteWordRight": (*BufPane).DeleteWordRight,
"DeleteWordLeft": (*BufPane).DeleteWordLeft,
"SelectLine": (*BufPane).SelectLine,
"SelectToStartOfLine": (*BufPane).SelectToStartOfLine,
"SelectToStartOfText": (*BufPane).SelectToStartOfText,
"SelectToStartOfTextToggle": (*BufPane).SelectToStartOfTextToggle,
"SelectToEndOfLine": (*BufPane).SelectToEndOfLine,
"ParagraphPrevious": (*BufPane).ParagraphPrevious,
"ParagraphNext": (*BufPane).ParagraphNext,
"InsertNewline": (*BufPane).InsertNewline,
"Backspace": (*BufPane).Backspace,
"Delete": (*BufPane).Delete,
"InsertTab": (*BufPane).InsertTab,
"Save": (*BufPane).Save,
"SaveAll": (*BufPane).SaveAll,
"SaveAs": (*BufPane).SaveAs,
"Find": (*BufPane).Find,
"FindLiteral": (*BufPane).FindLiteral,
"FindNext": (*BufPane).FindNext,
"FindPrevious": (*BufPane).FindPrevious,
"Center": (*BufPane).Center,
"Undo": (*BufPane).Undo,
"Redo": (*BufPane).Redo,
"Copy": (*BufPane).Copy,
"CopyLine": (*BufPane).CopyLine,
"Cut": (*BufPane).Cut,
"CutLine": (*BufPane).CutLine,
"DuplicateLine": (*BufPane).DuplicateLine,
"DeleteLine": (*BufPane).DeleteLine,
"MoveLinesUp": (*BufPane).MoveLinesUp,
"MoveLinesDown": (*BufPane).MoveLinesDown,
"IndentSelection": (*BufPane).IndentSelection,
"OutdentSelection": (*BufPane).OutdentSelection,
"Autocomplete": (*BufPane).Autocomplete,
"CycleAutocompleteBack": (*BufPane).CycleAutocompleteBack,
"OutdentLine": (*BufPane).OutdentLine,
"IndentLine": (*BufPane).IndentLine,
"Paste": (*BufPane).Paste,
"PastePrimary": (*BufPane).PastePrimary,
"SelectAll": (*BufPane).SelectAll,
"OpenFile": (*BufPane).OpenFile,
"Start": (*BufPane).Start,
"End": (*BufPane).End,
"PageUp": (*BufPane).PageUp,
"PageDown": (*BufPane).PageDown,
"SelectPageUp": (*BufPane).SelectPageUp,
"SelectPageDown": (*BufPane).SelectPageDown,
"HalfPageUp": (*BufPane).HalfPageUp,
"HalfPageDown": (*BufPane).HalfPageDown,
"StartOfText": (*BufPane).StartOfText,
"StartOfTextToggle": (*BufPane).StartOfTextToggle,
"StartOfLine": (*BufPane).StartOfLine,
"EndOfLine": (*BufPane).EndOfLine,
"ToggleHelp": (*BufPane).ToggleHelp,
"ToggleKeyMenu": (*BufPane).ToggleKeyMenu,
"ToggleDiffGutter": (*BufPane).ToggleDiffGutter,
"ToggleRuler": (*BufPane).ToggleRuler,
"ClearStatus": (*BufPane).ClearStatus,
"ShellMode": (*BufPane).ShellMode,
"CommandMode": (*BufPane).CommandMode,
"ToggleOverwriteMode": (*BufPane).ToggleOverwriteMode,
"Escape": (*BufPane).Escape,
"Quit": (*BufPane).Quit,
"QuitAll": (*BufPane).QuitAll,
"AddTab": (*BufPane).AddTab,
"PreviousTab": (*BufPane).PreviousTab,
"NextTab": (*BufPane).NextTab,
"NextSplit": (*BufPane).NextSplit,
"PreviousSplit": (*BufPane).PreviousSplit,
"Unsplit": (*BufPane).Unsplit,
"VSplit": (*BufPane).VSplitAction,
"HSplit": (*BufPane).HSplitAction,
"ToggleMacro": (*BufPane).ToggleMacro,
"PlayMacro": (*BufPane).PlayMacro,
"Suspend": (*BufPane).Suspend,
"ScrollUp": (*BufPane).ScrollUpAction,
"ScrollDown": (*BufPane).ScrollDownAction,
"SpawnMultiCursor": (*BufPane).SpawnMultiCursor,
"SpawnMultiCursorUp": (*BufPane).SpawnMultiCursorUp,
"SpawnMultiCursorDown": (*BufPane).SpawnMultiCursorDown,
"SpawnMultiCursorSelect": (*BufPane).SpawnMultiCursorSelect,
"RemoveMultiCursor": (*BufPane).RemoveMultiCursor,
"RemoveAllMultiCursors": (*BufPane).RemoveAllMultiCursors,
"SkipMultiCursor": (*BufPane).SkipMultiCursor,
"JumpToMatchingBrace": (*BufPane).JumpToMatchingBrace,
"JumpLine": (*BufPane).JumpLine,
"None": (*BufPane).None,
"CursorUp": (*BufPane).CursorUp,
"CursorDown": (*BufPane).CursorDown,
"CursorPageUp": (*BufPane).CursorPageUp,
"CursorPageDown": (*BufPane).CursorPageDown,
"CursorLeft": (*BufPane).CursorLeft,
"CursorRight": (*BufPane).CursorRight,
"CursorStart": (*BufPane).CursorStart,
"CursorEnd": (*BufPane).CursorEnd,
"SelectToStart": (*BufPane).SelectToStart,
"SelectToEnd": (*BufPane).SelectToEnd,
"SelectUp": (*BufPane).SelectUp,
"SelectDown": (*BufPane).SelectDown,
"SelectLeft": (*BufPane).SelectLeft,
"SelectRight": (*BufPane).SelectRight,
"WordRight": (*BufPane).WordRight,
"WordLeft": (*BufPane).WordLeft,
"SelectWordRight": (*BufPane).SelectWordRight,
"SelectWordLeft": (*BufPane).SelectWordLeft,
"DeleteWordRight": (*BufPane).DeleteWordRight,
"DeleteWordLeft": (*BufPane).DeleteWordLeft,
"SelectLine": (*BufPane).SelectLine,
"SelectToStartOfLine": (*BufPane).SelectToStartOfLine,
"SelectToStartOfText": (*BufPane).SelectToStartOfText,
"SelectToEndOfLine": (*BufPane).SelectToEndOfLine,
"ParagraphPrevious": (*BufPane).ParagraphPrevious,
"ParagraphNext": (*BufPane).ParagraphNext,
"InsertNewline": (*BufPane).InsertNewline,
"Backspace": (*BufPane).Backspace,
"Delete": (*BufPane).Delete,
"InsertTab": (*BufPane).InsertTab,
"Save": (*BufPane).Save,
"SaveAll": (*BufPane).SaveAll,
"SaveAs": (*BufPane).SaveAs,
"Find": (*BufPane).Find,
"FindNext": (*BufPane).FindNext,
"FindPrevious": (*BufPane).FindPrevious,
"Center": (*BufPane).Center,
"Undo": (*BufPane).Undo,
"Redo": (*BufPane).Redo,
"Copy": (*BufPane).Copy,
"Cut": (*BufPane).Cut,
"CutLine": (*BufPane).CutLine,
"DuplicateLine": (*BufPane).DuplicateLine,
"DeleteLine": (*BufPane).DeleteLine,
"MoveLinesUp": (*BufPane).MoveLinesUp,
"MoveLinesDown": (*BufPane).MoveLinesDown,
"IndentSelection": (*BufPane).IndentSelection,
"OutdentSelection": (*BufPane).OutdentSelection,
"Autocomplete": (*BufPane).Autocomplete,
"CycleAutocompleteBack": (*BufPane).CycleAutocompleteBack,
"OutdentLine": (*BufPane).OutdentLine,
"IndentLine": (*BufPane).IndentLine,
"Paste": (*BufPane).Paste,
"PastePrimary": (*BufPane).PastePrimary,
"SelectAll": (*BufPane).SelectAll,
"OpenFile": (*BufPane).OpenFile,
"Start": (*BufPane).Start,
"End": (*BufPane).End,
"PageUp": (*BufPane).PageUp,
"PageDown": (*BufPane).PageDown,
"SelectPageUp": (*BufPane).SelectPageUp,
"SelectPageDown": (*BufPane).SelectPageDown,
"HalfPageUp": (*BufPane).HalfPageUp,
"HalfPageDown": (*BufPane).HalfPageDown,
"StartOfText": (*BufPane).StartOfText,
"StartOfLine": (*BufPane).StartOfLine,
"EndOfLine": (*BufPane).EndOfLine,
"ToggleHelp": (*BufPane).ToggleHelp,
"ToggleKeyMenu": (*BufPane).ToggleKeyMenu,
"ToggleDiffGutter": (*BufPane).ToggleDiffGutter,
"ToggleRuler": (*BufPane).ToggleRuler,
"ClearStatus": (*BufPane).ClearStatus,
"ShellMode": (*BufPane).ShellMode,
"CommandMode": (*BufPane).CommandMode,
"ToggleOverwriteMode": (*BufPane).ToggleOverwriteMode,
"Escape": (*BufPane).Escape,
"Quit": (*BufPane).Quit,
"QuitAll": (*BufPane).QuitAll,
"AddTab": (*BufPane).AddTab,
"PreviousTab": (*BufPane).PreviousTab,
"NextTab": (*BufPane).NextTab,
"NextSplit": (*BufPane).NextSplit,
"PreviousSplit": (*BufPane).PreviousSplit,
"Unsplit": (*BufPane).Unsplit,
"VSplit": (*BufPane).VSplitAction,
"HSplit": (*BufPane).HSplitAction,
"ToggleMacro": (*BufPane).ToggleMacro,
"PlayMacro": (*BufPane).PlayMacro,
"Suspend": (*BufPane).Suspend,
"ScrollUp": (*BufPane).ScrollUpAction,
"ScrollDown": (*BufPane).ScrollDownAction,
"SpawnMultiCursor": (*BufPane).SpawnMultiCursor,
"SpawnMultiCursorUp": (*BufPane).SpawnMultiCursorUp,
"SpawnMultiCursorDown": (*BufPane).SpawnMultiCursorDown,
"SpawnMultiCursorSelect": (*BufPane).SpawnMultiCursorSelect,
"RemoveMultiCursor": (*BufPane).RemoveMultiCursor,
"RemoveAllMultiCursors": (*BufPane).RemoveAllMultiCursors,
"SkipMultiCursor": (*BufPane).SkipMultiCursor,
"JumpToMatchingBrace": (*BufPane).JumpToMatchingBrace,
"None": (*BufPane).None,
// This was changed to InsertNewline but I don't want to break backwards compatibility
"InsertEnter": (*BufPane).InsertNewline,
@@ -652,57 +628,54 @@ var BufMouseActions = map[string]BufMouseAction{
// Generally actions that modify global editor state like quitting or
// saving should not be included in this list
var MultiActions = map[string]bool{
"CursorUp": true,
"CursorDown": true,
"CursorPageUp": true,
"CursorPageDown": true,
"CursorLeft": true,
"CursorRight": true,
"CursorStart": true,
"CursorEnd": true,
"SelectToStart": true,
"SelectToEnd": true,
"SelectUp": true,
"SelectDown": true,
"SelectLeft": true,
"SelectRight": true,
"WordRight": true,
"WordLeft": true,
"SelectWordRight": true,
"SelectWordLeft": true,
"DeleteWordRight": true,
"DeleteWordLeft": true,
"SelectLine": true,
"SelectToStartOfLine": true,
"SelectToStartOfText": true,
"SelectToStartOfTextToggle": true,
"SelectToEndOfLine": true,
"ParagraphPrevious": true,
"ParagraphNext": true,
"InsertNewline": true,
"Backspace": true,
"Delete": true,
"InsertTab": true,
"FindNext": true,
"FindPrevious": true,
"CopyLine": true,
"Cut": true,
"CutLine": true,
"DuplicateLine": true,
"DeleteLine": true,
"MoveLinesUp": true,
"MoveLinesDown": true,
"IndentSelection": true,
"OutdentSelection": true,
"OutdentLine": true,
"IndentLine": true,
"Paste": true,
"PastePrimary": true,
"SelectPageUp": true,
"SelectPageDown": true,
"StartOfLine": true,
"StartOfText": true,
"StartOfTextToggle": true,
"EndOfLine": true,
"JumpToMatchingBrace": true,
"CursorUp": true,
"CursorDown": true,
"CursorPageUp": true,
"CursorPageDown": true,
"CursorLeft": true,
"CursorRight": true,
"CursorStart": true,
"CursorEnd": true,
"SelectToStart": true,
"SelectToEnd": true,
"SelectUp": true,
"SelectDown": true,
"SelectLeft": true,
"SelectRight": true,
"WordRight": true,
"WordLeft": true,
"SelectWordRight": true,
"SelectWordLeft": true,
"DeleteWordRight": true,
"DeleteWordLeft": true,
"SelectLine": true,
"SelectToStartOfLine": true,
"SelectToStartOfText": true,
"SelectToEndOfLine": true,
"ParagraphPrevious": true,
"ParagraphNext": true,
"InsertNewline": true,
"Backspace": true,
"Delete": true,
"InsertTab": true,
"FindNext": true,
"FindPrevious": true,
"Cut": true,
"CutLine": true,
"DuplicateLine": true,
"DeleteLine": true,
"MoveLinesUp": true,
"MoveLinesDown": true,
"IndentSelection": true,
"OutdentSelection": true,
"OutdentLine": true,
"IndentLine": true,
"Paste": true,
"PastePrimary": true,
"SelectPageUp": true,
"SelectPageDown": true,
"StartOfLine": true,
"StartOfText": true,
"EndOfLine": true,
"JumpToMatchingBrace": true,
}

View File

@@ -10,13 +10,14 @@ import (
"regexp"
"strconv"
"strings"
"unicode/utf8"
shellquote "github.com/kballard/go-shellquote"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/shell"
"github.com/zyedidia/micro/v2/internal/util"
"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"
)
// A Command contains information about how to execute a command
@@ -55,7 +56,6 @@ func InitCommands() {
"cd": {(*BufPane).CdCmd, buffer.FileComplete},
"pwd": {(*BufPane).PwdCmd, nil},
"open": {(*BufPane).OpenCmd, buffer.FileComplete},
"tabmove": {(*BufPane).TabMoveCmd, nil},
"tabswitch": {(*BufPane).TabSwitchCmd, nil},
"term": {(*BufPane).TermCmd, nil},
"memusage": {(*BufPane).MemUsageCmd, nil},
@@ -155,56 +155,6 @@ func (h *BufPane) TextFilterCmd(args []string) {
h.Buf.Insert(h.Cursor.Loc, bout.String())
}
// TabMoveCmd moves the current tab to a given index (starts at 1). The
// displaced tabs are moved up.
func (h *BufPane) TabMoveCmd(args []string) {
if len(args) <= 0 {
InfoBar.Error("Not enough arguments: provide an index, starting at 1")
return
}
if len(args[0]) <= 0 {
InfoBar.Error("Invalid argument: empty string")
return
}
num, err := strconv.Atoi(args[0])
if err != nil {
InfoBar.Error("Invalid argument: ", err)
return
}
// Preserve sign for relative move, if one exists
var shiftDirection byte
if strings.Contains("-+", string([]byte{args[0][0]})) {
shiftDirection = args[0][0]
}
// Relative positions -> absolute positions
idxFrom := Tabs.Active()
idxTo := 0
offset := util.Abs(num)
if shiftDirection == '-' {
idxTo = idxFrom - offset
} else if shiftDirection == '+' {
idxTo = idxFrom + offset
} else {
idxTo = offset - 1
}
// Restrain position to within the valid range
idxTo = util.Clamp(idxTo, 0, len(Tabs.List)-1)
activeTab := Tabs.List[idxFrom]
Tabs.RemoveTab(activeTab.ID())
Tabs.List = append(Tabs.List, nil)
copy(Tabs.List[idxTo+1:], Tabs.List[idxTo:])
Tabs.List[idxTo] = activeTab
Tabs.UpdateNames()
Tabs.SetActive(idxTo)
// InfoBar.Message(fmt.Sprintf("Moved tab from slot %d to %d", idxFrom+1, idxTo+1))
}
// TabSwitchCmd switches to a given tab either by name or by number
func (h *BufPane) TabSwitchCmd(args []string) {
if len(args) > 0 {
@@ -339,10 +289,7 @@ func ReloadConfig() {
if err != nil {
screen.TermMessage(err)
}
err = config.InitGlobalSettings()
if err != nil {
screen.TermMessage(err)
}
config.InitGlobalSettings()
InitBindings()
InitCommands()
@@ -480,7 +427,6 @@ func SetGlobalOptionNative(option string, nativeValue interface{}) error {
if !local {
config.GlobalSettings[option] = nativeValue
config.ModifiedSettings[option] = true
if option == "colorscheme" {
// LoadSyntaxFiles()
@@ -705,11 +651,8 @@ func (h *BufPane) GotoCmd(args []string) {
InfoBar.Error(err)
return
}
if line < 0 {
line = h.Buf.LinesNum() + 1 + line
}
line = util.Clamp(line-1, 0, h.Buf.LinesNum()-1)
col = util.Clamp(col-1, 0, util.CharacterCount(h.Buf.LineBytes(line)))
col = util.Clamp(col-1, 0, utf8.RuneCount(h.Buf.LineBytes(line)))
h.Cursor.GotoLoc(buffer.Loc{col, line})
} else {
line, err := strconv.Atoi(args[0])
@@ -717,9 +660,6 @@ func (h *BufPane) GotoCmd(args []string) {
InfoBar.Error(err)
return
}
if line < 0 {
line = h.Buf.LinesNum() + 1 + line
}
line = util.Clamp(line-1, 0, h.Buf.LinesNum()-1)
h.Cursor.GotoLoc(buffer.Loc{0, line})
}
@@ -793,8 +733,7 @@ func (h *BufPane) ReplaceCmd(args []string) {
nreplaced := 0
start := h.Buf.Start()
end := h.Buf.End()
selection := h.Cursor.HasSelection()
if selection {
if h.Cursor.HasSelection() {
start = h.Cursor.CurSelection[0]
end = h.Cursor.CurSelection[1]
}
@@ -821,9 +760,6 @@ func (h *BufPane) ReplaceCmd(args []string) {
h.Cursor.SetSelectionStart(locs[0])
h.Cursor.SetSelectionEnd(locs[1])
h.Cursor.GotoLoc(locs[0])
h.Relocate()
InfoBar.YNPrompt("Perform replacement (y,n,esc)", func(yes, canceled bool) {
if !canceled && yes {
@@ -836,7 +772,7 @@ func (h *BufPane) ReplaceCmd(args []string) {
nreplaced++
} else if !canceled && !yes {
searchLoc = locs[0]
searchLoc.X += util.CharacterCount(replace)
searchLoc.X += utf8.RuneCount(replace)
} else if canceled {
h.Cursor.ResetSelection()
h.Buf.RelocateCursors()
@@ -849,22 +785,14 @@ func (h *BufPane) ReplaceCmd(args []string) {
}
h.Buf.RelocateCursors()
h.Relocate()
var s string
if nreplaced > 1 {
s = fmt.Sprintf("Replaced %d occurrences of %s", nreplaced, search)
InfoBar.Message("Replaced ", nreplaced, " occurrences of ", search)
} else if nreplaced == 1 {
s = fmt.Sprintf("Replaced 1 occurrence of %s", search)
InfoBar.Message("Replaced ", nreplaced, " occurrence of ", search)
} else {
s = fmt.Sprintf("Nothing matched %s", search)
InfoBar.Message("Nothing matched ", search)
}
if selection {
s += " in selection"
}
InfoBar.Message(s)
}
// ReplaceAllCmd replaces search term all at once
@@ -893,11 +821,7 @@ func (h *BufPane) TermCmd(args []string) {
term := func(i int, newtab bool) {
t := new(shell.Terminal)
err := t.Start(args, false, true, nil, nil)
if err != nil {
InfoBar.Error(err)
return
}
t.Start(args, false, true, nil, nil)
id := h.ID()
if newtab {

View File

@@ -17,10 +17,10 @@ func DefaultBindings() map[string]string {
"AltDown": "MoveLinesDown",
"AltShiftRight": "SelectWordRight",
"AltShiftLeft": "SelectWordLeft",
"CtrlLeft": "StartOfTextToggle",
"CtrlLeft": "StartOfText",
"CtrlRight": "EndOfLine",
"CtrlShiftLeft": "SelectToStartOfTextToggle",
"ShiftHome": "SelectToStartOfTextToggle",
"CtrlShiftLeft": "SelectToStartOfText",
"ShiftHome": "SelectToStartOfText",
"CtrlShiftRight": "SelectToEndOfLine",
"ShiftEnd": "SelectToEndOfLine",
"CtrlUp": "CursorStart",
@@ -43,7 +43,7 @@ func DefaultBindings() map[string]string {
"CtrlP": "FindPrevious",
"CtrlZ": "Undo",
"CtrlY": "Redo",
"CtrlC": "CopyLine|Copy",
"CtrlC": "Copy",
"CtrlX": "Cut",
"CtrlK": "CutLine",
"CtrlD": "DuplicateLine",
@@ -52,7 +52,7 @@ func DefaultBindings() map[string]string {
"CtrlT": "AddTab",
"Alt,": "PreviousTab",
"Alt.": "NextTab",
"Home": "StartOfTextToggle",
"Home": "StartOfText",
"End": "EndOfLine",
"CtrlHome": "CursorStart",
"CtrlEnd": "CursorEnd",

View File

@@ -19,10 +19,10 @@ func DefaultBindings() map[string]string {
"AltDown": "MoveLinesDown",
"CtrlShiftRight": "SelectWordRight",
"CtrlShiftLeft": "SelectWordLeft",
"AltLeft": "StartOfTextToggle",
"AltLeft": "StartOfText",
"AltRight": "EndOfLine",
"AltShiftLeft": "SelectToStartOfTextToggle",
"ShiftHome": "SelectToStartOfTextToggle",
"AltShiftLeft": "SelectToStartOfText",
"ShiftHome": "SelectToStartOfText",
"AltShiftRight": "SelectToEndOfLine",
"ShiftEnd": "SelectToEndOfLine",
"CtrlUp": "CursorStart",
@@ -45,7 +45,7 @@ func DefaultBindings() map[string]string {
"CtrlP": "FindPrevious",
"CtrlZ": "Undo",
"CtrlY": "Redo",
"CtrlC": "CopyLine|Copy",
"CtrlC": "Copy",
"CtrlX": "Cut",
"CtrlK": "CutLine",
"CtrlD": "DuplicateLine",
@@ -54,7 +54,7 @@ func DefaultBindings() map[string]string {
"CtrlT": "AddTab",
"Alt,": "PreviousTab",
"Alt.": "NextTab",
"Home": "StartOfTextToggle",
"Home": "StartOfText",
"End": "EndOfLine",
"CtrlHome": "CursorStart",
"CtrlEnd": "CursorEnd",

View File

@@ -1,6 +1,6 @@
package action
import "github.com/zyedidia/micro/v2/internal/buffer"
import "github.com/zyedidia/micro/internal/buffer"
var InfoBar *InfoPane
var LogBufPane *BufPane

View File

@@ -5,9 +5,9 @@ import (
"sort"
"strings"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/buffer"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/util"
)
// This file is meant (for now) for autocompletion in command mode, not

View File

@@ -4,10 +4,9 @@ import (
"bytes"
"strings"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/display"
"github.com/zyedidia/micro/v2/internal/info"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/display"
"github.com/zyedidia/micro/internal/info"
"github.com/zyedidia/micro/internal/util"
"github.com/zyedidia/tcell"
)
@@ -187,17 +186,14 @@ func (h *InfoPane) Autocomplete() {
args := bytes.Split(l, []byte{' '})
cmd := string(args[0])
if h.PromptType == "Command" {
if len(args) == 1 {
b.Autocomplete(CommandComplete)
} else if action, ok := commands[cmd]; ok {
if len(args) == 1 {
b.Autocomplete(CommandComplete)
} else {
if action, ok := commands[cmd]; ok {
if action.completer != nil {
b.Autocomplete(action.completer)
}
}
} else {
// by default use filename autocompletion
b.Autocomplete(buffer.FileComplete)
}
}

View File

@@ -1,7 +1,7 @@
package action
import (
"github.com/zyedidia/micro/v2/internal/display"
"github.com/zyedidia/micro/internal/display"
)
type Pane interface {

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"reflect"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/display"
"github.com/zyedidia/micro/internal/buffer"
"github.com/zyedidia/micro/internal/display"
"github.com/zyedidia/tcell"
)

View File

@@ -1,11 +1,11 @@
package action
import (
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/display"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/views"
"github.com/zyedidia/micro/internal/buffer"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/display"
"github.com/zyedidia/micro/internal/screen"
"github.com/zyedidia/micro/internal/views"
"github.com/zyedidia/tcell"
)
@@ -166,8 +166,6 @@ type Tab struct {
active int
resizing *views.Node // node currently being resized
// captures whether the mouse is released
release bool
}
// NewTabFromBuffer creates a new tab from the given buffer
@@ -205,8 +203,6 @@ func (t *Tab) HandleEvent(event tcell.Event) {
mx, my := e.Position()
switch e.Buttons() {
case tcell.Button1:
wasReleased := t.release
t.release = false
if t.resizing != nil {
var size int
if t.resizing.Kind == views.STVert {
@@ -219,25 +215,22 @@ func (t *Tab) HandleEvent(event tcell.Event) {
return
}
if wasReleased {
resizeID := t.GetMouseSplitID(buffer.Loc{mx, my})
if resizeID != 0 {
t.resizing = t.GetNode(uint64(resizeID))
return
}
resizeID := t.GetMouseSplitID(buffer.Loc{mx, my})
if resizeID != 0 {
t.resizing = t.GetNode(uint64(resizeID))
return
}
for i, p := range t.Panes {
v := p.GetView()
inpane := mx >= v.X && mx < v.X+v.Width && my >= v.Y && my < v.Y+v.Height
if inpane {
t.SetActive(i)
break
}
for i, p := range t.Panes {
v := p.GetView()
inpane := mx >= v.X && mx < v.X+v.Width && my >= v.Y && my < v.Y+v.Height
if inpane {
t.SetActive(i)
break
}
}
case tcell.ButtonNone:
t.resizing = nil
t.release = true
default:
for _, p := range t.Panes {
v := p.GetView()

View File

@@ -4,7 +4,7 @@ package action
import (
shellquote "github.com/kballard/go-shellquote"
"github.com/zyedidia/micro/v2/internal/shell"
"github.com/zyedidia/micro/internal/shell"
)
// TermEmuSupported is a constant that marks if the terminal emulator is supported

View File

@@ -5,9 +5,9 @@ import (
"runtime"
"github.com/zyedidia/clipboard"
"github.com/zyedidia/micro/v2/internal/display"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/shell"
"github.com/zyedidia/micro/internal/display"
"github.com/zyedidia/micro/internal/screen"
"github.com/zyedidia/micro/internal/shell"
"github.com/zyedidia/tcell"
"github.com/zyedidia/terminal"
)

View File

@@ -6,8 +6,9 @@ import (
"os"
"sort"
"strings"
"unicode/utf8"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/util"
)
// A Completer is a function that takes a buffer and returns info
@@ -53,7 +54,7 @@ func (b *Buffer) CycleAutocomplete(forward bool) {
start := c.Loc
end := c.Loc
if prevSuggestion < len(b.Suggestions) && prevSuggestion >= 0 {
start = end.Move(-util.CharacterCountInString(b.Completions[prevSuggestion]), b)
start = end.Move(-utf8.RuneCountInString(b.Completions[prevSuggestion]), b)
} else {
// end = start.Move(1, b)
}
@@ -81,7 +82,7 @@ func GetWord(b *Buffer) ([]byte, int) {
args := bytes.FieldsFunc(l, util.IsNonAlphaNumeric)
input := args[len(args)-1]
return input, c.X - util.CharacterCount(input)
return input, c.X - utf8.RuneCount(input)
}
// GetArg gets the most recent word (separated by ' ' only)
@@ -97,7 +98,7 @@ func GetArg(b *Buffer) (string, int) {
if i == len(args)-1 {
break
}
argstart += util.CharacterCount(a) + 1
argstart += utf8.RuneCount(a) + 1
}
return input, argstart
@@ -161,7 +162,7 @@ func BufferComplete(b *Buffer) ([]string, []string) {
return []string{}, []string{}
}
inputLen := util.CharacterCount(input)
inputLen := utf8.RuneCount(input)
suggestionsSet := make(map[string]struct{})
@@ -170,7 +171,7 @@ func BufferComplete(b *Buffer) ([]string, []string) {
l := b.LineBytes(i)
words := bytes.FieldsFunc(l, util.IsNonAlphaNumeric)
for _, w := range words {
if bytes.HasPrefix(w, input) && util.CharacterCount(w) > inputLen {
if bytes.HasPrefix(w, input) && utf8.RuneCount(w) > inputLen {
strw := string(w)
if _, ok := suggestionsSet[strw]; !ok {
suggestionsSet[strw] = struct{}{}
@@ -183,7 +184,7 @@ func BufferComplete(b *Buffer) ([]string, []string) {
l := b.LineBytes(i)
words := bytes.FieldsFunc(l, util.IsNonAlphaNumeric)
for _, w := range words {
if bytes.HasPrefix(w, input) && util.CharacterCount(w) > inputLen {
if bytes.HasPrefix(w, input) && utf8.RuneCount(w) > inputLen {
strw := string(w)
if _, ok := suggestionsSet[strw]; !ok {
suggestionsSet[strw] = struct{}{}

View File

@@ -7,9 +7,9 @@ import (
"path/filepath"
"time"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/screen"
"github.com/zyedidia/micro/internal/util"
"golang.org/x/text/encoding"
)

View File

@@ -5,25 +5,25 @@ import (
"bytes"
"crypto/md5"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"unicode/utf8"
luar "layeh.com/gopher-luar"
dmp "github.com/sergi/go-diff/diffmatchpatch"
"github.com/zyedidia/micro/v2/internal/config"
ulua "github.com/zyedidia/micro/v2/internal/lua"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/v2/pkg/highlight"
"github.com/zyedidia/micro/internal/config"
ulua "github.com/zyedidia/micro/internal/lua"
"github.com/zyedidia/micro/internal/screen"
"github.com/zyedidia/micro/internal/util"
"github.com/zyedidia/micro/pkg/highlight"
"golang.org/x/text/encoding/htmlindex"
"golang.org/x/text/encoding/unicode"
"golang.org/x/text/transform"
@@ -60,9 +60,6 @@ var (
BTRaw = BufType{4, false, true, false}
// BTInfo is a buffer for inputting information
BTInfo = BufType{5, false, true, false}
// BTStdout is a buffer that only writes to stdout
// when closed
BTStdout = BufType{6, false, true, true}
// ErrFileTooLarge is returned when the file is too large to hash
// (fastdirty is automatically enabled)
@@ -78,34 +75,6 @@ type SharedBuffer struct {
// Type of the buffer (e.g. help, raw, scratch etc..)
Type BufType
// Path to the file on disk
Path string
// Absolute path to the file on disk
AbsPath string
// Name of the buffer on the status line
name string
toStdout bool
// Settings customized by the user
Settings map[string]interface{}
Suggestions []string
Completions []string
CurSuggestion int
Messages []*Message
updateDiffTimer *time.Timer
diffBase []byte
diffBaseLineCount int
diffLock sync.RWMutex
diff map[int]DiffStatus
// counts the number of edits
// resets every backupTime edits
lastbackup time.Time
// ReloadDisabled allows the user to disable reloads if they
// are viewing a file that is constantly changing
ReloadDisabled bool
@@ -115,13 +84,8 @@ type SharedBuffer struct {
// it changes based on how the buffer has changed
HasSuggestions bool
// The Highlighter struct actually performs the highlighting
Highlighter *highlight.Highlighter
// SyntaxDef represents the syntax highlighting definition being used
// This stores the highlighting rules and filetype detection info
SyntaxDef *highlight.Def
ModifiedThisFrame bool
// 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
@@ -132,35 +96,17 @@ func (b *SharedBuffer) insert(pos Loc, value []byte) {
b.HasSuggestions = false
b.LineArray.insert(pos, value)
inslines := bytes.Count(value, []byte{'\n'})
b.MarkModified(pos.Y, pos.Y+inslines)
// b.Modifications is cleared every screen redraw so it's
// ok to append duplicates
b.Modifications = append(b.Modifications, Loc{pos.Y, pos.Y + bytes.Count(value, []byte{'\n'})})
}
func (b *SharedBuffer) remove(start, end Loc) []byte {
b.isModified = true
b.HasSuggestions = false
defer b.MarkModified(start.Y, end.Y)
b.Modifications = append(b.Modifications, Loc{start.Y, start.Y})
return b.LineArray.remove(start, end)
}
// MarkModified marks the buffer as modified for this frame
// and performs rehighlighting if syntax highlighting is enabled
func (b *SharedBuffer) MarkModified(start, end int) {
b.ModifiedThisFrame = true
if !b.Settings["syntax"].(bool) || b.SyntaxDef == nil {
return
}
start = util.Clamp(start, 0, len(b.lines)-1)
end = util.Clamp(end, 0, len(b.lines)-1)
l := -1
for i := start; i <= end; i++ {
l = util.Max(b.Highlighter.ReHighlightStates(b, i), l)
}
b.Highlighter.HighlightMatches(b, start, l)
}
// DisableReload disables future reloads of this sharedbuffer
func (b *SharedBuffer) DisableReload() {
b.ReloadDisabled = true
@@ -189,24 +135,48 @@ type Buffer struct {
cursors []*Cursor
curCursor int
StartCursor Loc
// Path to the file on disk
Path string
// Absolute path to the file on disk
AbsPath string
// Name of the buffer on the status line
name string
// 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
HighlightLock sync.Mutex
// Settings customized by the user
Settings map[string]interface{}
Suggestions []string
Completions []string
CurSuggestion int
Messages []*Message
updateDiffTimer *time.Timer
diffBase []byte
diffBaseLineCount int
diffLock sync.RWMutex
diff map[int]DiffStatus
// counts the number of edits
// resets every backupTime edits
lastbackup time.Time
}
// NewBufferFromFileAtLoc opens a new buffer with a given cursor location
// If cursorLoc is {-1, -1} the location does not overwrite what the cursor location
// would otherwise be (start of file, or saved cursor position if `savecursor` is
// enabled)
func NewBufferFromFileAtLoc(path string, btype BufType, cursorLoc Loc) (*Buffer, error) {
// NewBufferFromFile opens a new buffer using the given path
// It will also automatically handle `~`, and line/column with filename:l:c
// It will return an empty buffer if the path does not exist
// and an error if the file is a directory
func NewBufferFromFile(path string, btype BufType) (*Buffer, error) {
var err error
filename := path
if config.GetGlobalOption("parsecursor").(bool) && cursorLoc.X == -1 && cursorLoc.Y == -1 {
var cursorPos []string
filename, cursorPos = util.GetPathAndCursorPosition(filename)
cursorLoc, err = ParseCursorLocation(cursorPos)
if err != nil {
cursorLoc = Loc{-1, -1}
}
}
filename, cursorPos := util.GetPathAndCursorPosition(path)
filename, err = util.ReplaceHome(filename)
if err != nil {
return nil, err
@@ -221,6 +191,11 @@ func NewBufferFromFileAtLoc(path string, btype BufType, cursorLoc Loc) (*Buffer,
defer file.Close()
cursorLoc, cursorerr := ParseCursorLocation(cursorPos)
if cursorerr != nil {
cursorLoc = Loc{-1, -1}
}
var buf *Buffer
if err != nil {
// File does not exist -- create an empty buffer with that name
@@ -232,19 +207,6 @@ func NewBufferFromFileAtLoc(path string, btype BufType, cursorLoc Loc) (*Buffer,
return buf, nil
}
// NewBufferFromFile opens a new buffer using the given path
// It will also automatically handle `~`, and line/column with filename:l:c
// It will return an empty buffer if the path does not exist
// and an error if the file is a directory
func NewBufferFromFile(path string, btype BufType) (*Buffer, error) {
return NewBufferFromFileAtLoc(path, btype, Loc{-1, -1})
}
// NewBufferFromStringAtLoc creates a new buffer containing the given string with a cursor loc
func NewBufferFromStringAtLoc(text, path string, btype BufType, cursorLoc Loc) *Buffer {
return NewBuffer(strings.NewReader(text), int64(len(text)), path, cursorLoc, btype)
}
// NewBufferFromString creates a new buffer containing the given string
func NewBufferFromString(text, path string, btype BufType) *Buffer {
return NewBuffer(strings.NewReader(text), int64(len(text)), path, Loc{-1, -1}, btype)
@@ -260,6 +222,23 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT
b := new(Buffer)
b.Settings = config.DefaultCommonSettings()
for k, v := range config.GlobalSettings {
if _, ok := config.DefaultGlobalOnlySettings[k]; !ok {
// make sure setting is not global-only
b.Settings[k] = v
}
}
config.InitLocalSettings(b.Settings, path)
enc, err := htmlindex.Get(b.Settings["encoding"].(string))
if err != nil {
enc = unicode.UTF8
b.Settings["encoding"] = "utf-8"
}
reader := bufio.NewReader(transform.NewReader(r, enc.NewDecoder()))
found := false
if len(path) > 0 {
for _, buf := range OpenBuffers {
@@ -271,58 +250,28 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT
}
}
b.Path = path
b.AbsPath = absPath
if !found {
b.SharedBuffer = new(SharedBuffer)
b.Type = btype
b.AbsPath = absPath
b.Path = path
b.Settings = config.DefaultCommonSettings()
for k, v := range config.GlobalSettings {
if _, ok := config.DefaultGlobalOnlySettings[k]; !ok {
// make sure setting is not global-only
b.Settings[k] = v
}
}
config.InitLocalSettings(b.Settings, path)
enc, err := htmlindex.Get(b.Settings["encoding"].(string))
if err != nil {
enc = unicode.UTF8
b.Settings["encoding"] = "utf-8"
}
hasBackup := b.ApplyBackup(size)
if !hasBackup {
reader := bufio.NewReader(transform.NewReader(r, enc.NewDecoder()))
var ff FileFormat = FFAuto
if size == 0 {
// for empty files, use the fileformat setting instead of
// autodetection
switch b.Settings["fileformat"] {
case "unix":
ff = FFUnix
case "dos":
ff = FFDos
}
}
b.LineArray = NewLineArray(uint64(size), ff, reader)
b.LineArray = NewLineArray(uint64(size), FFAuto, reader)
}
b.EventHandler = NewEventHandler(b.SharedBuffer, b.cursors)
// The last time this file was modified
b.UpdateModTime()
}
if b.Settings["readonly"].(bool) && b.Type == BTDefault {
b.Type.Readonly = true
}
// The last time this file was modified
b.UpdateModTime()
switch b.Endings {
case FFUnix:
b.Settings["fileformat"] = "unix"
@@ -331,7 +280,6 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT
}
b.UpdateRules()
// init local settings again now that we know the filetype
config.InitLocalSettings(b.Settings, b.Path)
if _, err := os.Stat(filepath.Join(config.ConfigDir, "buffers")); os.IsNotExist(err) {
@@ -352,7 +300,7 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT
b.AddCursor(NewCursor(b, b.StartCursor))
b.GetActiveCursor().Relocate()
if !b.Settings["fastdirty"].(bool) && !found {
if !b.Settings["fastdirty"].(bool) {
if size > LargeFileThreshold {
// If the file is larger than LargeFileThreshold fastdirty needs to be on
b.Settings["fastdirty"] = true
@@ -361,11 +309,13 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT
}
}
err := config.RunPluginFn("onBufferOpen", luar.New(ulua.L, b))
err = config.RunPluginFn("onBufferOpen", luar.New(ulua.L, b))
if err != nil {
screen.TermMessage(err)
}
b.Modifications = make([]Loc, 0, 10)
OpenBuffers = append(OpenBuffers, b)
return b
@@ -391,26 +341,18 @@ func (b *Buffer) Fini() {
b.Serialize()
}
b.RemoveBackup()
if b.Type == BTStdout {
fmt.Fprint(util.Stdout, string(b.Bytes()))
}
}
// GetName returns the name that should be displayed in the statusline
// for this buffer
func (b *Buffer) GetName() string {
name := b.name
if name == "" {
if b.name == "" {
if b.Path == "" {
return "No name"
}
name = b.Path
return b.Path
}
if b.Settings["basename"].(bool) {
return path.Base(name)
}
return name
return b.name
}
//SetName changes the name for this buffer
@@ -440,6 +382,16 @@ func (b *Buffer) Remove(start, end Loc) {
}
}
// 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)
@@ -504,7 +456,7 @@ func (b *Buffer) RuneAt(loc Loc) rune {
if len(line) > 0 {
i := 0
for len(line) > 0 {
r, _, size := util.DecodeCharacter(line)
r, size := utf8.DecodeRune(line)
line = line[size:]
i++
@@ -578,37 +530,7 @@ func (b *Buffer) UpdateRules() {
return
}
syntaxFile := ""
foundDef := false
var header *highlight.Header
// search for the syntax file in the user's custom syntax files
for _, f := range config.ListRealRuntimeFiles(config.RTSyntax) {
data, err := f.Data()
if err != nil {
screen.TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
continue
}
header, err = highlight.MakeHeaderYaml(data)
file, err := highlight.ParseFile(data)
if err != nil {
screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error())
continue
}
if ((ft == "unknown" || ft == "") && highlight.MatchFiletype(header.FtDetect, b.Path, b.lines[0].data)) || header.FileType == ft {
syndef, err := highlight.ParseDef(file, header)
if err != nil {
screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error())
continue
}
b.SyntaxDef = syndef
syntaxFile = f.Name()
foundDef = true
break
}
}
// search in the default syntax files
for _, f := range config.ListRuntimeFiles(config.RTSyntaxHeader) {
data, err := f.Data()
if err != nil {
@@ -633,8 +555,34 @@ func (b *Buffer) UpdateRules() {
}
}
if syntaxFile != "" && !foundDef {
// we found a syntax file using a syntax header file
if syntaxFile == "" {
// search for the syntax file in the user's custom syntax files
for _, f := range config.ListRealRuntimeFiles(config.RTSyntax) {
log.Println("real runtime file", f.Name())
data, err := f.Data()
if err != nil {
screen.TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
continue
}
header, err = highlight.MakeHeaderYaml(data)
file, err := highlight.ParseFile(data)
if err != nil {
screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error())
continue
}
if ((ft == "unknown" || ft == "") && highlight.MatchFiletype(header.FtDetect, b.Path, b.lines[0].data)) || header.FileType == ft {
syndef, err := highlight.ParseDef(file, header)
if err != nil {
screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error())
continue
}
b.SyntaxDef = syndef
break
}
}
} else {
for _, f := range config.ListRuntimeFiles(config.RTSyntax) {
if f.Name() == syntaxFile {
data, err := f.Data()
@@ -828,6 +776,7 @@ func (b *Buffer) ClearCursors() {
b.UpdateCursors()
b.curCursor = 0
b.GetActiveCursor().ResetSelection()
log.Println("Cleared cursors:", len(b.cursors))
}
// MoveLinesUp moves the range of lines up one row
@@ -839,7 +788,7 @@ func (b *Buffer) MoveLinesUp(start int, end int) {
if end == len(b.lines) {
b.Insert(
Loc{
util.CharacterCount(b.lines[end-1].data),
utf8.RuneCount(b.lines[end-1].data),
end - 1,
},
"\n"+l,
@@ -973,7 +922,7 @@ func (b *Buffer) Retab() {
l = bytes.TrimLeft(l, " \t")
b.lines[i].data = append(ws, l...)
b.MarkModified(i, i)
b.Modifications = append(b.Modifications, Loc{i, i})
dirty = true
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,322 +0,0 @@
package buffer
import (
"math/rand"
"strings"
"testing"
"github.com/stretchr/testify/assert"
lua "github.com/yuin/gopher-lua"
"github.com/zyedidia/micro/v2/internal/config"
ulua "github.com/zyedidia/micro/v2/internal/lua"
"github.com/zyedidia/micro/v2/internal/util"
)
type operation struct {
start Loc
end Loc
text []string
}
func init() {
ulua.L = lua.NewState()
config.InitGlobalSettings()
config.GlobalSettings["backup"] = false
config.GlobalSettings["fastdirty"] = true
}
func check(t *testing.T, before []string, operations []operation, after []string) {
assert := assert.New(t)
b := NewBufferFromString(strings.Join(before, "\n"), "", BTDefault)
assert.NotEqual("", b.GetName())
assert.Equal(false, b.ExternallyModified())
assert.Equal(false, b.Modified())
assert.Equal(1, b.NumCursors())
checkText := func(lines []string) {
assert.Equal([]byte(strings.Join(lines, "\n")), b.Bytes())
assert.Equal(len(lines), b.LinesNum())
for i, s := range lines {
assert.Equal(s, b.Line(i))
assert.Equal([]byte(s), b.LineBytes(i))
}
}
checkText(before)
var cursors []*Cursor
for _, op := range operations {
cursor := NewCursor(b, op.start)
cursor.SetSelectionStart(op.start)
cursor.SetSelectionEnd(op.end)
b.AddCursor(cursor)
cursors = append(cursors, cursor)
}
assert.Equal(1+len(operations), b.NumCursors())
for i, op := range operations {
cursor := cursors[i]
b.SetCurCursor(cursor.Num)
cursor.DeleteSelection()
b.Insert(cursor.Loc, strings.Join(op.text, "\n"))
}
checkText(after)
// must have exactly two events per operation (delete and insert)
for range operations {
b.UndoOneEvent()
b.UndoOneEvent()
}
checkText(before)
for i, op := range operations {
cursor := cursors[i]
if op.start == op.end {
assert.Equal(op.start, cursor.Loc)
} else {
assert.Equal(op.start, cursor.CurSelection[0])
assert.Equal(op.end, cursor.CurSelection[1])
}
}
for range operations {
b.RedoOneEvent()
b.RedoOneEvent()
}
checkText(after)
b.Close()
}
const maxLineLength = 200
var alphabet = []rune(" abcdeäم📚")
func randomString(length int) string {
runes := make([]rune, length)
for i := range runes {
runes[i] = alphabet[rand.Intn(len(alphabet))]
}
return string(runes)
}
func randomText(nLines int) string {
lines := make([]string, nLines)
for i := range lines {
lines[i] = randomString(rand.Intn(maxLineLength + 1))
}
return strings.Join(lines, "\n")
}
func benchCreateAndClose(testingB *testing.B, nLines int) {
rand.Seed(int64(nLines))
text := randomText(nLines)
testingB.ResetTimer()
for i := 0; i < testingB.N; i++ {
b := NewBufferFromString(text, "", BTDefault)
b.Close()
}
}
func benchRead(testingB *testing.B, nLines int) {
rand.Seed(int64(nLines))
b := NewBufferFromString(randomText(nLines), "", BTDefault)
testingB.ResetTimer()
for i := 0; i < testingB.N; i++ {
b.Bytes()
for j := 0; j < b.LinesNum(); j++ {
b.Line(j)
b.LineBytes(j)
}
}
testingB.StopTimer()
b.Close()
}
func benchEdit(testingB *testing.B, nLines, nCursors int) {
rand.Seed(int64(nLines + nCursors))
b := NewBufferFromString(randomText(nLines), "", BTDefault)
regionSize := nLines / nCursors
operations := make([]operation, nCursors)
for i := range operations {
startLine := (i * regionSize) + rand.Intn(regionSize-5)
startColumn := rand.Intn(util.CharacterCountInString(b.Line(startLine)) + 1)
endLine := startLine + 1 + rand.Intn(5)
endColumn := rand.Intn(util.CharacterCountInString(b.Line(endLine)) + 1)
operations[i] = operation{
start: Loc{startColumn, startLine},
end: Loc{endColumn, endLine},
text: []string{randomText(2 + rand.Intn(4))},
}
}
testingB.ResetTimer()
for i := 0; i < testingB.N; i++ {
b.SetCursors([]*Cursor{})
var cursors []*Cursor
for _, op := range operations {
cursor := NewCursor(b, op.start)
cursor.SetSelectionStart(op.start)
cursor.SetSelectionEnd(op.end)
b.AddCursor(cursor)
cursors = append(cursors, cursor)
}
for j, op := range operations {
cursor := cursors[j]
b.SetCurCursor(cursor.Num)
cursor.DeleteSelection()
b.Insert(cursor.Loc, op.text[0])
}
for b.UndoStack.Peek() != nil {
b.UndoOneEvent()
}
}
testingB.StopTimer()
b.Close()
}
func BenchmarkCreateAndClose10Lines(b *testing.B) {
benchCreateAndClose(b, 10)
}
func BenchmarkCreateAndClose100Lines(b *testing.B) {
benchCreateAndClose(b, 100)
}
func BenchmarkCreateAndClose1000Lines(b *testing.B) {
benchCreateAndClose(b, 1000)
}
func BenchmarkCreateAndClose10000Lines(b *testing.B) {
benchCreateAndClose(b, 10000)
}
func BenchmarkCreateAndClose100000Lines(b *testing.B) {
benchCreateAndClose(b, 100000)
}
func BenchmarkCreateAndClose1000000Lines(b *testing.B) {
benchCreateAndClose(b, 1000000)
}
func BenchmarkRead10Lines(b *testing.B) {
benchRead(b, 10)
}
func BenchmarkRead100Lines(b *testing.B) {
benchRead(b, 100)
}
func BenchmarkRead1000Lines(b *testing.B) {
benchRead(b, 1000)
}
func BenchmarkRead10000Lines(b *testing.B) {
benchRead(b, 10000)
}
func BenchmarkRead100000Lines(b *testing.B) {
benchRead(b, 100000)
}
func BenchmarkRead1000000Lines(b *testing.B) {
benchRead(b, 1000000)
}
func BenchmarkEdit10Lines1Cursor(b *testing.B) {
benchEdit(b, 10, 1)
}
func BenchmarkEdit100Lines1Cursor(b *testing.B) {
benchEdit(b, 100, 1)
}
func BenchmarkEdit100Lines10Cursors(b *testing.B) {
benchEdit(b, 100, 10)
}
func BenchmarkEdit1000Lines1Cursor(b *testing.B) {
benchEdit(b, 1000, 1)
}
func BenchmarkEdit1000Lines10Cursors(b *testing.B) {
benchEdit(b, 1000, 10)
}
func BenchmarkEdit1000Lines100Cursors(b *testing.B) {
benchEdit(b, 1000, 100)
}
func BenchmarkEdit10000Lines1Cursor(b *testing.B) {
benchEdit(b, 10000, 1)
}
func BenchmarkEdit10000Lines10Cursors(b *testing.B) {
benchEdit(b, 10000, 10)
}
func BenchmarkEdit10000Lines100Cursors(b *testing.B) {
benchEdit(b, 10000, 100)
}
func BenchmarkEdit10000Lines1000Cursors(b *testing.B) {
benchEdit(b, 10000, 1000)
}
func BenchmarkEdit100000Lines1Cursor(b *testing.B) {
benchEdit(b, 100000, 1)
}
func BenchmarkEdit100000Lines10Cursors(b *testing.B) {
benchEdit(b, 100000, 10)
}
func BenchmarkEdit100000Lines100Cursors(b *testing.B) {
benchEdit(b, 100000, 100)
}
func BenchmarkEdit100000Lines1000Cursors(b *testing.B) {
benchEdit(b, 100000, 1000)
}
func BenchmarkEdit1000000Lines1Cursor(b *testing.B) {
benchEdit(b, 1000000, 1)
}
func BenchmarkEdit1000000Lines10Cursors(b *testing.B) {
benchEdit(b, 1000000, 10)
}
func BenchmarkEdit1000000Lines100Cursors(b *testing.B) {
benchEdit(b, 1000000, 100)
}
func BenchmarkEdit1000000Lines1000Cursors(b *testing.B) {
benchEdit(b, 1000000, 1000)
}

View File

@@ -1,13 +1,15 @@
package buffer
import (
"unicode/utf8"
"github.com/zyedidia/clipboard"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/util"
)
// InBounds returns whether the given location is a valid character position in the given buffer
func InBounds(pos Loc, buf *Buffer) bool {
if pos.Y < 0 || pos.Y >= len(buf.lines) || pos.X < 0 || pos.X > util.CharacterCount(buf.LineBytes(pos.Y)) {
if pos.Y < 0 || pos.Y >= len(buf.lines) || pos.X < 0 || pos.X > utf8.RuneCount(buf.LineBytes(pos.Y)) {
return false
}
@@ -74,6 +76,9 @@ func (c *Cursor) GetVisualX() int {
bytes := c.buf.LineBytes(c.Y)
tabsize := int(c.buf.Settings["tabsize"].(float64))
if c.X > utf8.RuneCount(bytes) {
c.X = utf8.RuneCount(bytes) - 1
}
return util.StringWidth(bytes, c.X, tabsize)
}
@@ -97,29 +102,16 @@ func (c *Cursor) Start() {
func (c *Cursor) StartOfText() {
c.Start()
for util.IsWhitespace(c.RuneUnder(c.X)) {
if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) {
if c.X == utf8.RuneCount(c.buf.LineBytes(c.Y)) {
break
}
c.Right()
}
}
// IsStartOfText returns whether the cursor is at the first
// non-whitespace rune of the line it is on
func (c *Cursor) IsStartOfText() bool {
x := 0
for util.IsWhitespace(c.RuneUnder(x)) {
if x == util.CharacterCount(c.buf.LineBytes(c.Y)) {
break
}
x++
}
return c.X == x
}
// End moves the cursor to the end of the line it is on
func (c *Cursor) End() {
c.X = util.CharacterCount(c.buf.LineBytes(c.Y))
c.X = utf8.RuneCount(c.buf.LineBytes(c.Y))
c.LastVisualX = c.GetVisualX()
}
@@ -237,14 +229,8 @@ func (c *Cursor) UpN(amount int) {
bytes := c.buf.LineBytes(proposedY)
c.X = c.GetCharPosInLine(bytes, c.LastVisualX)
if c.X > util.CharacterCount(bytes) || (amount < 0 && proposedY == c.Y) {
c.X = util.CharacterCount(bytes)
c.StoreVisualX()
}
if c.X < 0 || (amount > 0 && proposedY == c.Y) {
c.X = 0
c.StoreVisualX()
if c.X > utf8.RuneCount(bytes) || (amount < 0 && proposedY == c.Y) {
c.X = utf8.RuneCount(bytes)
}
c.Y = proposedY
@@ -286,7 +272,7 @@ func (c *Cursor) Right() {
if c.Loc == c.buf.End() {
return
}
if c.X < util.CharacterCount(c.buf.LineBytes(c.Y)) {
if c.X < utf8.RuneCount(c.buf.LineBytes(c.Y)) {
c.X++
} else {
c.Down()
@@ -307,8 +293,8 @@ func (c *Cursor) Relocate() {
if c.X < 0 {
c.X = 0
} else if c.X > util.CharacterCount(c.buf.LineBytes(c.Y)) {
c.X = util.CharacterCount(c.buf.LineBytes(c.Y))
} else if c.X > utf8.RuneCount(c.buf.LineBytes(c.Y)) {
c.X = utf8.RuneCount(c.buf.LineBytes(c.Y))
}
}
@@ -334,7 +320,7 @@ func (c *Cursor) SelectWord() {
c.SetSelectionStart(Loc{backward, c.Y})
c.OrigSelection[0] = c.CurSelection[0]
lineLen := util.CharacterCount(c.buf.LineBytes(c.Y)) - 1
lineLen := utf8.RuneCount(c.buf.LineBytes(c.Y)) - 1
for forward < lineLen && util.IsWordChar(c.RuneUnder(forward+1)) {
forward++
}
@@ -366,7 +352,7 @@ func (c *Cursor) AddWordToSelection() {
if c.Loc.GreaterThan(c.OrigSelection[1]) {
forward := c.X
lineLen := util.CharacterCount(c.buf.LineBytes(c.Y)) - 1
lineLen := utf8.RuneCount(c.buf.LineBytes(c.Y)) - 1
for forward < lineLen && util.IsWordChar(c.RuneUnder(forward+1)) {
forward++
}
@@ -393,7 +379,7 @@ func (c *Cursor) SelectTo(loc Loc) {
// WordRight moves the cursor one word to the right
func (c *Cursor) WordRight() {
for util.IsWhitespace(c.RuneUnder(c.X)) {
if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) {
if c.X == utf8.RuneCount(c.buf.LineBytes(c.Y)) {
c.Right()
return
}
@@ -401,7 +387,7 @@ func (c *Cursor) WordRight() {
}
c.Right()
for util.IsWordChar(c.RuneUnder(c.X)) {
if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) {
if c.X == utf8.RuneCount(c.buf.LineBytes(c.Y)) {
return
}
c.Right()
@@ -430,14 +416,14 @@ func (c *Cursor) WordLeft() {
// RuneUnder returns the rune under the given x position
func (c *Cursor) RuneUnder(x int) rune {
line := c.buf.LineBytes(c.Y)
if len(line) == 0 || x >= util.CharacterCount(line) {
if len(line) == 0 || x >= utf8.RuneCount(line) {
return '\n'
} else if x < 0 {
x = 0
}
i := 0
for len(line) > 0 {
r, _, size := util.DecodeCharacter(line)
r, size := utf8.DecodeRune(line)
line = line[size:]
if i == x {

View File

@@ -3,12 +3,12 @@ package buffer
import (
"bytes"
"time"
"unicode/utf8"
dmp "github.com/sergi/go-diff/diffmatchpatch"
"github.com/zyedidia/micro/v2/internal/config"
ulua "github.com/zyedidia/micro/v2/internal/lua"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/config"
ulua "github.com/zyedidia/micro/internal/lua"
"github.com/zyedidia/micro/internal/screen"
luar "layeh.com/gopher-luar"
)
@@ -41,73 +41,6 @@ type Delta struct {
End Loc
}
// DoTextEvent runs a text event
func (eh *EventHandler) DoTextEvent(t *TextEvent, useUndo bool) {
oldl := eh.buf.LinesNum()
if useUndo {
eh.Execute(t)
} else {
ExecuteTextEvent(t, eh.buf)
}
if len(t.Deltas) != 1 {
return
}
text := t.Deltas[0].Text
start := t.Deltas[0].Start
lastnl := -1
var endX int
var textX int
if t.EventType == TextEventInsert {
linecount := eh.buf.LinesNum() - oldl
textcount := util.CharacterCount(text)
lastnl = bytes.LastIndex(text, []byte{'\n'})
if lastnl >= 0 {
endX = util.CharacterCount(text[lastnl+1:])
textX = endX
} else {
endX = start.X + textcount
textX = textcount
}
t.Deltas[0].End = clamp(Loc{endX, start.Y + linecount}, eh.buf.LineArray)
}
end := t.Deltas[0].End
for _, c := range eh.cursors {
move := func(loc Loc) Loc {
if t.EventType == TextEventInsert {
if start.Y != loc.Y && loc.GreaterThan(start) {
loc.Y += end.Y - start.Y
} else if loc.Y == start.Y && loc.GreaterEqual(start) {
loc.Y += end.Y - start.Y
if lastnl >= 0 {
loc.X += textX - start.X
} else {
loc.X += textX
}
}
return loc
} else {
if loc.Y != end.Y && loc.GreaterThan(end) {
loc.Y -= end.Y - start.Y
} else if loc.Y == end.Y && loc.GreaterEqual(end) {
loc = loc.MoveLA(-DiffLA(start, end, eh.buf.LineArray), eh.buf.LineArray)
}
return loc
}
}
c.Loc = move(c.Loc)
c.CurSelection[0] = move(c.CurSelection[0])
c.CurSelection[1] = move(c.CurSelection[1])
c.OrigSelection[0] = move(c.OrigSelection[0])
c.OrigSelection[1] = move(c.OrigSelection[1])
c.Relocate()
c.LastVisualX = c.GetVisualX()
}
}
// ExecuteTextEvent runs a text event
func ExecuteTextEvent(t *TextEvent, buf *SharedBuffer) {
if t.EventType == TextEventInsert {
@@ -123,7 +56,7 @@ func ExecuteTextEvent(t *TextEvent, buf *SharedBuffer) {
t.Deltas[i].Text = buf.remove(d.Start, d.End)
buf.insert(d.Start, d.Text)
t.Deltas[i].Start = d.Start
t.Deltas[i].End = Loc{d.Start.X + util.CharacterCount(d.Text), d.Start.Y}
t.Deltas[i].End = Loc{d.Start.X + utf8.RuneCount(d.Text), d.Start.Y}
}
for i, j := 0, len(t.Deltas)-1; i < j; i, j = i+1, j-1 {
t.Deltas[i], t.Deltas[j] = t.Deltas[j], t.Deltas[i]
@@ -132,9 +65,9 @@ func ExecuteTextEvent(t *TextEvent, buf *SharedBuffer) {
}
// UndoTextEvent undoes a text event
func (eh *EventHandler) UndoTextEvent(t *TextEvent) {
func UndoTextEvent(t *TextEvent, buf *SharedBuffer) {
t.EventType = -t.EventType
eh.DoTextEvent(t, false)
ExecuteTextEvent(t, buf)
}
// EventHandler executes text manipulations and allows undoing and redoing
@@ -166,12 +99,12 @@ func (eh *EventHandler) ApplyDiff(new string) {
loc := eh.buf.Start()
for _, d := range diff {
if d.Type == dmp.DiffDelete {
eh.Remove(loc, loc.MoveLA(util.CharacterCountInString(d.Text), eh.buf.LineArray))
eh.Remove(loc, loc.MoveLA(utf8.RuneCountInString(d.Text), eh.buf.LineArray))
} else {
if d.Type == dmp.DiffInsert {
eh.Insert(loc, d.Text)
}
loc = loc.MoveLA(util.CharacterCountInString(d.Text), eh.buf.LineArray)
loc = loc.MoveLA(utf8.RuneCountInString(d.Text), eh.buf.LineArray)
}
}
}
@@ -184,9 +117,6 @@ func (eh *EventHandler) Insert(start Loc, textStr string) {
// InsertBytes creates an insert text event and executes it
func (eh *EventHandler) InsertBytes(start Loc, text []byte) {
if len(text) == 0 {
return
}
start = clamp(start, eh.buf.LineArray)
e := &TextEvent{
C: *eh.cursors[eh.active],
@@ -194,14 +124,50 @@ func (eh *EventHandler) InsertBytes(start Loc, text []byte) {
Deltas: []Delta{{text, start, Loc{0, 0}}},
Time: time.Now(),
}
eh.DoTextEvent(e, true)
oldl := eh.buf.LinesNum()
eh.Execute(e)
linecount := eh.buf.LinesNum() - oldl
textcount := utf8.RuneCount(text)
lastnl := bytes.LastIndex(text, []byte{'\n'})
var endX int
var textX int
if lastnl >= 0 {
endX = utf8.RuneCount(text[lastnl+1:])
textX = endX
} else {
endX = start.X + textcount
textX = textcount
}
e.Deltas[0].End = clamp(Loc{endX, start.Y + linecount}, eh.buf.LineArray)
end := e.Deltas[0].End
for _, c := range eh.cursors {
move := func(loc Loc) Loc {
if start.Y != end.Y && loc.GreaterThan(start) {
loc.Y += end.Y - start.Y
} else if loc.Y == start.Y && loc.GreaterEqual(start) {
loc.Y += end.Y - start.Y
if lastnl >= 0 {
loc.X = textX
} else {
loc.X += textX
}
}
return loc
}
c.Loc = move(c.Loc)
c.Relocate()
c.CurSelection[0] = move(c.CurSelection[0])
c.CurSelection[1] = move(c.CurSelection[1])
c.OrigSelection[0] = move(c.OrigSelection[0])
c.OrigSelection[1] = move(c.OrigSelection[1])
c.LastVisualX = c.GetVisualX()
}
}
// Remove creates a remove text event and executes it
func (eh *EventHandler) Remove(start, end Loc) {
if start == end {
return
}
start = clamp(start, eh.buf.LineArray)
end = clamp(end, eh.buf.LineArray)
e := &TextEvent{
@@ -210,7 +176,24 @@ func (eh *EventHandler) Remove(start, end Loc) {
Deltas: []Delta{{[]byte{}, start, end}},
Time: time.Now(),
}
eh.DoTextEvent(e, true)
eh.Execute(e)
for _, c := range eh.cursors {
move := func(loc Loc) Loc {
if start.Y != end.Y && loc.GreaterThan(end) {
loc.Y -= end.Y - start.Y
} else if loc.Y == end.Y && loc.GreaterEqual(end) {
loc = loc.MoveLA(-DiffLA(start, end, eh.buf.LineArray), eh.buf.LineArray)
}
return loc
}
c.Loc = move(c.Loc)
c.CurSelection[0] = move(c.CurSelection[0])
c.CurSelection[1] = move(c.CurSelection[1])
c.OrigSelection[0] = move(c.OrigSelection[0])
c.OrigSelection[1] = move(c.OrigSelection[1])
c.LastVisualX = c.GetVisualX()
}
}
// MultipleReplace creates an multiple insertions executes them
@@ -281,9 +264,10 @@ func (eh *EventHandler) UndoOneEvent() {
if t == nil {
return
}
// Undo it
// Modifies the text event
eh.UndoTextEvent(t)
UndoTextEvent(t, eh.buf)
// Set the cursor in the right place
teCursor := t.C
@@ -329,6 +313,9 @@ func (eh *EventHandler) RedoOneEvent() {
return
}
// Modifies the text event
UndoTextEvent(t, eh.buf)
teCursor := t.C
if teCursor.Num >= 0 && teCursor.Num < len(eh.cursors) {
t.C = *eh.cursors[teCursor.Num]
@@ -337,8 +324,5 @@ func (eh *EventHandler) RedoOneEvent() {
teCursor.Num = -1
}
// Modifies the text event
eh.UndoTextEvent(t)
eh.UndoStack.Push(t)
}

View File

@@ -2,12 +2,11 @@ package buffer
import (
"bufio"
"bytes"
"io"
"sync"
"unicode/utf8"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/v2/pkg/highlight"
"github.com/zyedidia/micro/pkg/highlight"
)
// Finds the byte index of the nth rune in a byte slice
@@ -19,7 +18,7 @@ func runeToByteIndex(n int, txt []byte) int {
count := 0
i := 0
for len(txt) > 0 {
_, _, size := util.DecodeCharacter(txt)
_, size := utf8.DecodeRune(txt)
txt = txt[size:]
count += size
@@ -87,8 +86,6 @@ func NewLineArray(size uint64, endings FileFormat, reader io.Reader) *LineArray
br := bufio.NewReader(reader)
var loaded int
la.Endings = endings
n := 0
for {
data, err := br.ReadBytes('\n')
@@ -155,19 +152,17 @@ func NewLineArray(size uint64, endings FileFormat, reader io.Reader) *LineArray
// Bytes returns the string that should be written to disk when
// the line array is saved
func (la *LineArray) Bytes() []byte {
b := new(bytes.Buffer)
// initsize should provide a good estimate
b.Grow(int(la.initsize + 4096))
str := make([]byte, 0, la.initsize+1000) // initsize should provide a good estimate
for i, l := range la.lines {
b.Write(l.data)
str = append(str, l.data...)
if i != len(la.lines)-1 {
if la.Endings == FFDos {
b.WriteByte('\r')
str = append(str, '\r')
}
b.WriteByte('\n')
str = append(str, '\n')
}
}
return b.Bytes()
return str
}
// newlineBelow adds a newline below the given line number
@@ -301,7 +296,7 @@ func (la *LineArray) Start() Loc {
// End returns the location of the last character in the buffer
func (la *LineArray) End() Loc {
numlines := len(la.lines)
return Loc{util.CharacterCount(la.lines[numlines-1].data), numlines - 1}
return Loc{utf8.RuneCount(la.lines[numlines-1].data), numlines - 1}
}
// LineBytes returns line n as an array of bytes

View File

@@ -46,15 +46,14 @@ func TestInsert(t *testing.T) {
assert.Equal(t, []byte("Uppen Sevarne staþe, foobar sel þar him þuhte,"), sub1)
la.insert(Loc{25, 2}, []byte("H̼̥̯͇͙̕͘͞e̸̦̞̠̣̰͙̼̥̦̼̖̬͕͕̰̯̫͇̕ĺ̜̠̩̯̯͙̼̭̠͕̮̞͜l̶͓̫̞̮͈͞ͅo̸͔͙̳̠͈̮̼̳͙̥̲͜͠"))
la.insert(Loc{25, 2}, []byte("ಮಣ್ಣಾಗಿ"))
sub2 := la.Substr(Loc{0, 2}, Loc{60, 2})
assert.Equal(t, []byte("He wonede at Ernleȝe at æH̼̥̯͇͙̕͘͞e̸̦̞̠̣̰͙̼̥̦̼̖̬͕͕̰̯̫͇̕ĺ̜̠̩̯̯͙̼̭̠͕̮̞͜l̶͓̫̞̮͈͞ͅo̸͔͙̳̠͈̮̼̳͙̥̲͜͠ðelen are chirechen,"), sub2)
assert.Equal(t, []byte("He wonede at Ernleȝe at æಮಣ್ಣಾಗಿðelen are chirechen,"), sub2)
}
func TestRemove(t *testing.T) {
la.remove(Loc{20, 3}, Loc{27, 3})
la.remove(Loc{25, 2}, Loc{30, 2})
la.remove(Loc{25, 2}, Loc{32, 2})
bytes := la.Bytes()
assert.Equal(t, unicode_txt, string(bytes))

View File

@@ -1,7 +1,9 @@
package buffer
import (
"github.com/zyedidia/micro/v2/internal/util"
"unicode/utf8"
"github.com/zyedidia/micro/internal/util"
)
// Loc stores a location
@@ -66,9 +68,9 @@ func DiffLA(a, b Loc, buf *LineArray) int {
loc := 0
for i := a.Y + 1; i < b.Y; i++ {
// + 1 for the newline
loc += util.CharacterCount(buf.LineBytes(i)) + 1
loc += utf8.RuneCount(buf.LineBytes(i)) + 1
}
loc += util.CharacterCount(buf.LineBytes(a.Y)) - a.X + b.X + 1
loc += utf8.RuneCount(buf.LineBytes(a.Y)) - a.X + b.X + 1
return loc
}
@@ -78,7 +80,7 @@ func (l Loc) right(buf *LineArray) Loc {
return Loc{l.X + 1, l.Y}
}
var res Loc
if l.X < util.CharacterCount(buf.LineBytes(l.Y)) {
if l.X < utf8.RuneCount(buf.LineBytes(l.Y)) {
res = Loc{l.X + 1, l.Y}
} else {
res = Loc{0, l.Y + 1}
@@ -95,7 +97,7 @@ func (l Loc) left(buf *LineArray) Loc {
if l.X > 0 {
res = Loc{l.X - 1, l.Y}
} else {
res = Loc{util.CharacterCount(buf.LineBytes(l.Y - 1)), l.Y - 1}
res = Loc{utf8.RuneCount(buf.LineBytes(l.Y - 1)), l.Y - 1}
}
return res
}

View File

@@ -1,7 +1,7 @@
package buffer
import (
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/tcell"
)

View File

@@ -11,10 +11,11 @@ import (
"path/filepath"
"runtime"
"unicode"
"unicode/utf8"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/screen"
"github.com/zyedidia/micro/internal/util"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/htmlindex"
"golang.org/x/text/transform"
@@ -96,11 +97,12 @@ func (b *Buffer) saveToFile(filename string, withSudo bool) error {
return errors.New("Save with sudo not supported on Windows")
}
b.UpdateRules()
if b.Settings["rmtrailingws"].(bool) {
for i, l := range b.lines {
leftover := util.CharacterCount(bytes.TrimRightFunc(l.data, unicode.IsSpace))
leftover := utf8.RuneCount(bytes.TrimRightFunc(l.data, unicode.IsSpace))
linelen := util.CharacterCount(l.data)
linelen := utf8.RuneCount(l.data)
b.Remove(Loc{leftover, i}, Loc{linelen, i})
}
@@ -109,8 +111,8 @@ func (b *Buffer) saveToFile(filename string, withSudo bool) error {
if b.Settings["eofnewline"].(bool) {
end := b.End()
if b.RuneAt(Loc{end.X, end.Y}) != '\n' {
b.insert(end, []byte{'\n'})
if b.RuneAt(Loc{end.X - 1, end.Y}) != '\n' {
b.Insert(end, "\n")
}
}
@@ -194,6 +196,5 @@ func (b *Buffer) saveToFile(filename string, withSudo bool) error {
absPath, _ := filepath.Abs(filename)
b.AbsPath = absPath
b.isModified = false
b.UpdateRules()
return err
}

View File

@@ -2,8 +2,9 @@ package buffer
import (
"regexp"
"unicode/utf8"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/util"
)
func (b *Buffer) findDown(r *regexp.Regexp, start, end Loc) ([2]Loc, bool) {
@@ -19,19 +20,19 @@ func (b *Buffer) findDown(r *regexp.Regexp, start, end Loc) ([2]Loc, bool) {
charpos := 0
if i == start.Y && start.Y == end.Y {
nchars := util.CharacterCount(l)
nchars := utf8.RuneCount(l)
start.X = util.Clamp(start.X, 0, nchars)
end.X = util.Clamp(end.X, 0, nchars)
l = util.SliceStart(l, end.X)
l = util.SliceEnd(l, start.X)
charpos = start.X
} else if i == start.Y {
nchars := util.CharacterCount(l)
nchars := utf8.RuneCount(l)
start.X = util.Clamp(start.X, 0, nchars)
l = util.SliceEnd(l, start.X)
charpos = start.X
} else if i == end.Y {
nchars := util.CharacterCount(l)
nchars := utf8.RuneCount(l)
end.X = util.Clamp(end.X, 0, nchars)
l = util.SliceStart(l, end.X)
}
@@ -60,19 +61,19 @@ func (b *Buffer) findUp(r *regexp.Regexp, start, end Loc) ([2]Loc, bool) {
charpos := 0
if i == start.Y && start.Y == end.Y {
nchars := util.CharacterCount(l)
nchars := utf8.RuneCount(l)
start.X = util.Clamp(start.X, 0, nchars)
end.X = util.Clamp(end.X, 0, nchars)
l = util.SliceStart(l, end.X)
l = util.SliceEnd(l, start.X)
charpos = start.X
} else if i == start.Y {
nchars := util.CharacterCount(l)
nchars := utf8.RuneCount(l)
start.X = util.Clamp(start.X, 0, nchars)
l = util.SliceEnd(l, start.X)
charpos = start.X
} else if i == end.Y {
nchars := util.CharacterCount(l)
nchars := utf8.RuneCount(l)
end.X = util.Clamp(end.X, 0, nchars)
l = util.SliceStart(l, end.X)
}
@@ -162,12 +163,12 @@ func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []b
result = search.Expand(result, replace, in, submatches)
}
found++
netrunes += util.CharacterCount(in) - util.CharacterCount(result)
netrunes += utf8.RuneCount(in) - utf8.RuneCount(result)
return result
})
from := Loc{charpos, i}
to := Loc{charpos + util.CharacterCount(l), i}
to := Loc{charpos + utf8.RuneCount(l), i}
deltas = append(deltas, Delta{newText, from, to})
}

View File

@@ -10,8 +10,8 @@ import (
"golang.org/x/text/encoding"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/util"
)
// The SerializedBuffer holds the types that get serialized when a buffer is saved

View File

@@ -1,8 +1,8 @@
package buffer
import (
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/screen"
)
func (b *Buffer) SetOptionNative(option string, nativeValue interface{}) error {

View File

@@ -151,9 +151,6 @@ func StringToStyle(str string) tcell.Style {
if strings.Contains(str, "bold") {
style = style.Bold(true)
}
if strings.Contains(str, "italic") {
style = style.Italic(true)
}
if strings.Contains(str, "reverse") {
style = style.Reverse(true)
}

View File

@@ -5,7 +5,7 @@ import (
"log"
lua "github.com/yuin/gopher-lua"
ulua "github.com/zyedidia/micro/v2/internal/lua"
ulua "github.com/zyedidia/micro/internal/lua"
)
// ErrNoSuchFunction is returned when Call is executed on a function that does not exist

View File

@@ -16,8 +16,8 @@ import (
"github.com/blang/semver"
lua "github.com/yuin/gopher-lua"
"github.com/zyedidia/json5"
ulua "github.com/zyedidia/micro/v2/internal/lua"
"github.com/zyedidia/micro/v2/internal/util"
ulua "github.com/zyedidia/micro/internal/lua"
"github.com/zyedidia/micro/internal/util"
)
var (

File diff suppressed because one or more lines are too long

View File

@@ -3,7 +3,6 @@ package config
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
@@ -13,7 +12,7 @@ import (
"github.com/zyedidia/glob"
"github.com/zyedidia/json5"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/util"
"golang.org/x/text/encoding/htmlindex"
)
@@ -28,14 +27,9 @@ var (
// This is the raw parsed json
parsedSettings map[string]interface{}
// ModifiedSettings is a map of settings which should be written to disk
// because they have been modified by the user in this session
ModifiedSettings map[string]bool
)
func init() {
ModifiedSettings = make(map[string]bool)
parsedSettings = make(map[string]interface{})
}
@@ -81,33 +75,16 @@ func ReadSettings() error {
return nil
}
func verifySetting(option string, value reflect.Type, def reflect.Type) bool {
var interfaceArr []interface{}
switch option {
case "pluginrepos", "pluginchannels":
return value.AssignableTo(reflect.TypeOf(interfaceArr))
default:
return def.AssignableTo(value)
}
}
// InitGlobalSettings initializes the options map and sets all options to their default values
// Must be called after ReadSettings
func InitGlobalSettings() error {
var err error
func InitGlobalSettings() {
GlobalSettings = DefaultGlobalSettings()
for k, v := range parsedSettings {
if !strings.HasPrefix(reflect.TypeOf(v).String(), "map") {
if _, ok := GlobalSettings[k]; ok && !verifySetting(k, reflect.TypeOf(v), reflect.TypeOf(GlobalSettings[k])) {
err = errors.New(fmt.Sprintf("Global Error: setting '%s' has incorrect type (%s), using default value: %v (%s)", k, reflect.TypeOf(v), GlobalSettings[k], reflect.TypeOf(GlobalSettings[k])))
continue
}
GlobalSettings[k] = v
}
}
return err
}
// InitLocalSettings scans the json in settings.json and sets the options locally based
@@ -120,10 +97,6 @@ func InitLocalSettings(settings map[string]interface{}, path string) error {
if strings.HasPrefix(k, "ft:") {
if settings["filetype"].(string) == k[3:] {
for k1, v1 := range v.(map[string]interface{}) {
if _, ok := settings[k1]; ok && !verifySetting(k1, reflect.TypeOf(v1), reflect.TypeOf(settings[k1])) {
parseError = errors.New(fmt.Sprintf("Error: setting '%s' has incorrect type (%s), using default value: %v (%s)", k, reflect.TypeOf(v1), settings[k1], reflect.TypeOf(settings[k1])))
continue
}
settings[k1] = v1
}
}
@@ -136,10 +109,6 @@ func InitLocalSettings(settings map[string]interface{}, path string) error {
if g.MatchString(path) {
for k1, v1 := range v.(map[string]interface{}) {
if _, ok := settings[k1]; ok && !verifySetting(k1, reflect.TypeOf(v1), reflect.TypeOf(settings[k1])) {
parseError = errors.New(fmt.Sprintf("Error: setting '%s' has incorrect type (%s), using default value: %v (%s)", k, reflect.TypeOf(v1), settings[k1], reflect.TypeOf(settings[k1])))
continue
}
settings[k1] = v1
}
}
@@ -153,25 +122,8 @@ func InitLocalSettings(settings map[string]interface{}, path string) error {
func WriteSettings(filename string) error {
var err error
if _, e := os.Stat(ConfigDir); e == nil {
defaults := DefaultGlobalSettings()
// remove any options froms parsedSettings that have since been marked as default
for k, v := range parsedSettings {
if !strings.HasPrefix(reflect.TypeOf(v).String(), "map") {
cur, okcur := GlobalSettings[k]
if def, ok := defaults[k]; ok && okcur && reflect.DeepEqual(cur, def) {
delete(parsedSettings, k)
}
}
}
// add any options to parsedSettings that have since been marked as non-default
for k, v := range GlobalSettings {
if def, ok := defaults[k]; !ok || !reflect.DeepEqual(v, def) {
if _, wr := ModifiedSettings[k]; wr {
parsedSettings[k] = v
}
}
parsedSettings[k] = v
}
txt, _ := json.MarshalIndent(parsedSettings, "", " ")
@@ -180,23 +132,10 @@ func WriteSettings(filename string) error {
return err
}
// OverwriteSettings writes the current settings to settings.json and
// resets any user configuration of local settings present in settings.json
func OverwriteSettings(filename string) error {
settings := make(map[string]interface{})
var err error
if _, e := os.Stat(ConfigDir); e == nil {
defaults := DefaultGlobalSettings()
for k, v := range GlobalSettings {
if def, ok := defaults[k]; !ok || !reflect.DeepEqual(v, def) {
if _, wr := ModifiedSettings[k]; wr {
settings[k] = v
}
}
}
txt, _ := json.MarshalIndent(settings, "", " ")
txt, _ := json.MarshalIndent(GlobalSettings, "", " ")
err = ioutil.WriteFile(filename, append(txt, '\n'), 0644)
}
return err
@@ -252,7 +191,7 @@ var defaultCommonSettings = map[string]interface{}{
"cursorline": true,
"diffgutter": false,
"encoding": "utf-8",
"eofnewline": true,
"eofnewline": false,
"fastdirty": false,
"fileformat": "unix",
"filetype": "unknown",
@@ -264,7 +203,6 @@ var defaultCommonSettings = map[string]interface{}{
"readonly": false,
"rmtrailingws": false,
"ruler": true,
"relativeruler": false,
"savecursor": false,
"saveundo": false,
"scrollbar": false,
@@ -310,12 +248,9 @@ func DefaultCommonSettings() map[string]interface{} {
var DefaultGlobalOnlySettings = map[string]interface{}{
"autosave": float64(0),
"colorscheme": "default",
"divchars": "|-",
"divreverse": true,
"infobar": true,
"keymenu": false,
"mouse": true,
"parsecursor": false,
"paste": false,
"savehistory": true,
"sucmd": "sudo",

View File

@@ -2,12 +2,13 @@ package display
import (
"strconv"
"unicode/utf8"
runewidth "github.com/mattn/go-runewidth"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/buffer"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/screen"
"github.com/zyedidia/micro/internal/util"
"github.com/zyedidia/tcell"
)
@@ -72,9 +73,9 @@ func (w *BufWindow) getStartInfo(n, lineN int) ([]byte, int, int, *tcell.Style)
curStyle := config.DefStyle
var s *tcell.Style
for len(b) > 0 {
r, _, size := util.DecodeCharacter(b)
r, size := utf8.DecodeRune(b)
curStyle, found := w.getStyle(curStyle, bloc)
curStyle, found := w.getStyle(curStyle, bloc, r)
if found {
s = &curStyle
}
@@ -236,7 +237,7 @@ func (w *BufWindow) LocFromVisual(svloc buffer.Loc) buffer.Loc {
return bloc
}
r, _, size := util.DecodeCharacter(line)
r, size := utf8.DecodeRune(line)
draw()
width := 0
@@ -335,14 +336,7 @@ func (w *BufWindow) drawDiffGutter(backgroundStyle tcell.Style, softwrapped bool
}
func (w *BufWindow) drawLineNum(lineNumStyle tcell.Style, softwrapped bool, maxLineNumLength int, vloc *buffer.Loc, bloc *buffer.Loc) {
cursorLine := w.Buf.GetActiveCursor().Loc.Y
var lineInt int
if w.Buf.Settings["relativeruler"] == false || cursorLine == bloc.Y {
lineInt = bloc.Y + 1
} else {
lineInt = bloc.Y - cursorLine
}
lineNum := strconv.Itoa(util.Abs(lineInt))
lineNum := strconv.Itoa(bloc.Y + 1)
// Write the spaces before the line number if necessary
for i := 0; i < maxLineNumLength-len(lineNum); i++ {
@@ -366,7 +360,7 @@ func (w *BufWindow) drawLineNum(lineNumStyle tcell.Style, softwrapped bool, maxL
// getStyle returns the highlight style for the given character position
// If there is no change to the current highlight style it just returns that
func (w *BufWindow) getStyle(style tcell.Style, bloc buffer.Loc) (tcell.Style, bool) {
func (w *BufWindow) getStyle(style tcell.Style, bloc buffer.Loc, r rune) (tcell.Style, bool) {
if group, ok := w.Buf.Match(bloc.Y)[bloc.X]; ok {
s := config.GetColor(group.String())
return s, true
@@ -403,7 +397,21 @@ func (w *BufWindow) displayBuffer() {
bufWidth--
}
if b.ModifiedThisFrame {
if len(b.Modifications) > 0 {
if b.Settings["syntax"].(bool) && b.SyntaxDef != nil {
for _, r := range b.Modifications {
rx := util.Clamp(r.X, 0, b.LinesNum())
ry := util.Clamp(r.Y, 0, b.LinesNum())
final := -1
for i := rx; i <= ry; i++ {
final = util.Max(b.Highlighter.ReHighlightStates(b, i), final)
}
b.Highlighter.HighlightMatches(b, rx, final+1)
}
}
b.ClearModifications()
if b.Settings["diffgutter"].(bool) {
b.UpdateDiff(func(synchronous bool) {
// If the diff was updated asynchronously, the outer call to
@@ -418,7 +426,6 @@ func (w *BufWindow) displayBuffer() {
}
})
}
b.ModifiedThisFrame = false
}
var matchingBraces []buffer.Loc
@@ -516,7 +523,7 @@ func (w *BufWindow) displayBuffer() {
}
bloc.X = bslice
draw := func(r rune, combc []rune, style tcell.Style, showcursor bool) {
draw := func(r rune, style tcell.Style, showcursor bool) {
if nColsBeforeStart <= 0 {
for _, c := range cursors {
if c.HasSelection() &&
@@ -562,7 +569,7 @@ func (w *BufWindow) displayBuffer() {
}
if s, ok := config.Colorscheme["color-column"]; ok {
if colorcolumn != 0 && vloc.X-w.gutterOffset+w.StartCol == colorcolumn {
if colorcolumn != 0 && vloc.X-w.gutterOffset == colorcolumn {
fg, _, _ := s.Decompose()
style = style.Background(fg)
}
@@ -574,7 +581,7 @@ func (w *BufWindow) displayBuffer() {
}
}
screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, r, combc, style)
screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, r, nil, style)
if showcursor {
for _, c := range cursors {
@@ -590,11 +597,10 @@ func (w *BufWindow) displayBuffer() {
totalwidth := w.StartCol - nColsBeforeStart
for len(line) > 0 {
r, combc, size := util.DecodeCharacter(line)
r, size := utf8.DecodeRune(line)
curStyle, _ = w.getStyle(curStyle, bloc, r)
curStyle, _ = w.getStyle(curStyle, bloc)
draw(r, combc, curStyle, true)
draw(r, curStyle, true)
width := 0
@@ -611,7 +617,7 @@ func (w *BufWindow) displayBuffer() {
// Draw any extra characters either spaces for tabs or @ for incomplete wide runes
if width > 1 {
for i := 1; i < width; i++ {
draw(char, nil, curStyle, false)
draw(char, curStyle, false)
}
}
bloc.X++
@@ -657,7 +663,7 @@ func (w *BufWindow) displayBuffer() {
for i := vloc.X; i < bufWidth; i++ {
curStyle := style
if s, ok := config.Colorscheme["color-column"]; ok {
if colorcolumn != 0 && i-w.gutterOffset+w.StartCol == colorcolumn {
if colorcolumn != 0 && i-w.gutterOffset == colorcolumn {
fg, _, _ := s.Decompose()
curStyle = style.Background(fg)
}
@@ -666,8 +672,7 @@ func (w *BufWindow) displayBuffer() {
}
if vloc.X != bufWidth {
// Display newline within a selection
draw(' ', nil, config.DefStyle, true)
draw(' ', curStyle, true)
}
bloc.X = w.StartCol
@@ -690,27 +695,8 @@ func (w *BufWindow) displayStatusLine() {
w.sline.Display()
} else if w.Y+w.Height != infoY {
w.drawStatus = true
divchars := config.GetGlobalOption("divchars").(string)
if util.CharacterCountInString(divchars) != 2 {
divchars = "|-"
}
_, _, size := util.DecodeCharacterInString(divchars)
divchar, combc, _ := util.DecodeCharacterInString(divchars[size:])
dividerStyle := config.DefStyle
if style, ok := config.Colorscheme["divider"]; ok {
dividerStyle = style
}
divreverse := config.GetGlobalOption("divreverse").(bool)
if divreverse {
dividerStyle = dividerStyle.Reverse(true)
}
for x := w.X; x < w.X+w.Width; x++ {
screen.SetContent(x, w.Y+w.Height-1, divchar, combc, dividerStyle)
screen.SetContent(x, w.Y+w.Height-1, '-', nil, config.DefStyle.Reverse(true))
}
} else {
w.drawStatus = false

View File

@@ -1,12 +1,14 @@
package display
import (
"unicode/utf8"
runewidth "github.com/mattn/go-runewidth"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/info"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/buffer"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/info"
"github.com/zyedidia/micro/internal/screen"
"github.com/zyedidia/micro/internal/util"
"github.com/zyedidia/tcell"
)
@@ -68,7 +70,7 @@ func (i *InfoWindow) IsActive() bool { return true }
func (i *InfoWindow) LocFromVisual(vloc buffer.Loc) buffer.Loc {
c := i.Buffer.GetActiveCursor()
l := i.Buffer.LineBytes(0)
n := util.CharacterCountInString(i.Msg)
n := utf8.RuneCountInString(i.Msg)
return buffer.Loc{c.GetCharPosInLine(l, vloc.X-n), 0}
}
@@ -84,13 +86,13 @@ func (i *InfoWindow) displayBuffer() {
activeC := b.GetActiveCursor()
blocX := 0
vlocX := util.CharacterCountInString(i.Msg)
vlocX := utf8.RuneCountInString(i.Msg)
tabsize := 4
line, nColsBeforeStart, bslice := util.SliceVisualEnd(line, blocX, tabsize)
blocX = bslice
draw := func(r rune, combc []rune, style tcell.Style) {
draw := func(r rune, style tcell.Style) {
if nColsBeforeStart <= 0 {
bloc := buffer.Loc{X: blocX, Y: 0}
if activeC.HasSelection() &&
@@ -110,9 +112,8 @@ func (i *InfoWindow) displayBuffer() {
c := r
if j > 0 {
c = ' '
combc = nil
}
screen.SetContent(vlocX, i.Y, c, combc, style)
screen.SetContent(vlocX, i.Y, c, nil, style)
}
vlocX++
}
@@ -123,9 +124,9 @@ func (i *InfoWindow) displayBuffer() {
for len(line) > 0 {
curVX := vlocX
curBX := blocX
r, combc, size := util.DecodeCharacter(line)
r, size := utf8.DecodeRune(line)
draw(r, combc, i.defStyle())
draw(r, i.defStyle())
width := 0
@@ -145,7 +146,7 @@ func (i *InfoWindow) displayBuffer() {
// Draw any extra characters either spaces for tabs or @ for incomplete wide runes
if width > 1 {
for j := 1; j < width; j++ {
draw(char, nil, i.defStyle())
draw(char, i.defStyle())
}
}
if activeC.X == curBX {
@@ -190,7 +191,7 @@ func (i *InfoWindow) scrollToSuggestion() {
s := i.totalSize()
for j, n := range i.Suggestions {
c := util.CharacterCountInString(n)
c := utf8.RuneCountInString(n)
if j == i.CurSuggestion {
if x+c >= i.hscroll+i.Width {
i.hscroll = util.Clamp(x+c+1-i.Width, 0, s-i.Width)
@@ -208,13 +209,13 @@ func (i *InfoWindow) scrollToSuggestion() {
}
func (i *InfoWindow) Display() {
if i.HasPrompt || config.GlobalSettings["infobar"].(bool) {
i.Clear()
x := 0
if config.GetGlobalOption("keymenu").(bool) {
i.displayKeyMenu()
}
i.Clear()
x := 0
if config.GetGlobalOption("keymenu").(bool) {
i.displayKeyMenu()
}
if i.HasPrompt || config.GlobalSettings["infobar"].(bool) {
if !i.HasPrompt && !i.HasMessage && !i.HasError {
return
}

View File

@@ -3,19 +3,21 @@ package display
import (
"bytes"
"fmt"
"path"
"regexp"
"strconv"
"strings"
"unicode/utf8"
luar "layeh.com/gopher-luar"
runewidth "github.com/mattn/go-runewidth"
lua "github.com/yuin/gopher-lua"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
ulua "github.com/zyedidia/micro/v2/internal/lua"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/buffer"
"github.com/zyedidia/micro/internal/config"
ulua "github.com/zyedidia/micro/internal/lua"
"github.com/zyedidia/micro/internal/screen"
"github.com/zyedidia/micro/internal/util"
)
// StatusLine represents the information line at the bottom
@@ -30,6 +32,9 @@ type StatusLine struct {
var statusInfo = map[string]func(*buffer.Buffer) string{
"filename": func(b *buffer.Buffer) string {
if b.Settings["basename"].(bool) {
return path.Base(b.GetName())
}
return b.GetName()
},
"line": func(b *buffer.Buffer) string {
@@ -167,36 +172,34 @@ func (s *StatusLine) Display() {
statusLineStyle = style
}
leftLen := util.StringWidth(leftText, util.CharacterCount(leftText), 1)
rightLen := util.StringWidth(rightText, util.CharacterCount(rightText), 1)
leftLen := util.StringWidth(leftText, utf8.RuneCount(leftText), 1)
rightLen := util.StringWidth(rightText, utf8.RuneCount(rightText), 1)
winX := s.win.X
for x := 0; x < s.win.Width; x++ {
if x < leftLen {
r, combc, size := util.DecodeCharacter(leftText)
r, size := utf8.DecodeRune(leftText)
leftText = leftText[size:]
rw := runewidth.RuneWidth(r)
for j := 0; j < rw; j++ {
c := r
if j > 0 {
c = ' '
combc = nil
x++
}
screen.SetContent(winX+x, y, c, combc, statusLineStyle)
screen.SetContent(winX+x, y, c, nil, statusLineStyle)
}
} else if x >= s.win.Width-rightLen && x < rightLen+s.win.Width-rightLen {
r, combc, size := util.DecodeCharacter(rightText)
r, size := utf8.DecodeRune(rightText)
rightText = rightText[size:]
rw := runewidth.RuneWidth(r)
for j := 0; j < rw; j++ {
c := r
if j > 0 {
c = ' '
combc = nil
x++
}
screen.SetContent(winX+x, y, c, combc, statusLineStyle)
screen.SetContent(winX+x, y, c, nil, statusLineStyle)
}
} else {
screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)

View File

@@ -1,11 +1,13 @@
package display
import (
"unicode/utf8"
runewidth "github.com/mattn/go-runewidth"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/buffer"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/screen"
"github.com/zyedidia/micro/internal/util"
)
type TabWindow struct {
@@ -32,7 +34,7 @@ func (w *TabWindow) LocFromVisual(vloc buffer.Loc) int {
for i, n := range w.Names {
x++
s := util.CharacterCountInString(n)
s := utf8.RuneCountInString(n)
if vloc.Y == w.Y && vloc.X < x+s {
return i
}
@@ -73,7 +75,7 @@ func (w *TabWindow) SetActive(a int) {
s := w.TotalSize()
for i, n := range w.Names {
c := util.CharacterCountInString(n)
c := utf8.RuneCountInString(n)
if i == a {
if x+c >= w.hscroll+w.Width {
w.hscroll = util.Clamp(x+c+1-w.Width, 0, s-w.Width)
@@ -94,11 +96,6 @@ func (w *TabWindow) Display() {
x := -w.hscroll
done := false
tabBarStyle := config.DefStyle.Reverse(true)
if style, ok := config.Colorscheme["tabbar"]; ok {
tabBarStyle = style
}
draw := func(r rune, n int) {
for i := 0; i < n; i++ {
rw := runewidth.RuneWidth(r)
@@ -108,13 +105,13 @@ func (w *TabWindow) Display() {
c = ' '
}
if x == w.Width-1 && !done {
screen.SetContent(w.Width-1, w.Y, '>', nil, tabBarStyle)
screen.SetContent(w.Width-1, w.Y, '>', nil, config.DefStyle.Reverse(true))
x++
break
} else if x == 0 && w.hscroll > 0 {
screen.SetContent(0, w.Y, '<', nil, tabBarStyle)
screen.SetContent(0, w.Y, '<', nil, config.DefStyle.Reverse(true))
} else if x >= 0 && x < w.Width {
screen.SetContent(x, w.Y, c, nil, tabBarStyle)
screen.SetContent(x, w.Y, c, nil, config.DefStyle.Reverse(true))
}
x++
}

View File

@@ -1,11 +1,12 @@
package display
import (
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/shell"
"github.com/zyedidia/micro/v2/internal/util"
"unicode/utf8"
"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/tcell"
"github.com/zyedidia/terminal"
)
@@ -97,12 +98,12 @@ func (w *TermWindow) Display() {
}
text := []byte(w.Name())
textLen := util.CharacterCount(text)
textLen := utf8.RuneCount(text)
for x := 0; x < w.Width; x++ {
if x < textLen {
r, combc, size := util.DecodeCharacter(text)
r, size := utf8.DecodeRune(text)
text = text[size:]
screen.SetContent(w.X+x, w.Y+w.Height, r, combc, statusLineStyle)
screen.SetContent(w.X+x, w.Y+w.Height, r, nil, statusLineStyle)
} else {
screen.SetContent(w.X+x, w.Y+w.Height, ' ', nil, statusLineStyle)
}

View File

@@ -1,11 +1,10 @@
package display
import (
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/v2/internal/views"
"github.com/zyedidia/micro/internal/buffer"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/screen"
"github.com/zyedidia/micro/internal/views"
)
type UIWindow struct {
@@ -25,23 +24,11 @@ func (w *UIWindow) drawNode(n *views.Node) {
dividerStyle = style
}
divchars := config.GetGlobalOption("divchars").(string)
if util.CharacterCountInString(divchars) != 2 {
divchars = "|-"
}
divchar, combc, _ := util.DecodeCharacterInString(divchars)
divreverse := config.GetGlobalOption("divreverse").(bool)
if divreverse {
dividerStyle = dividerStyle.Reverse(true)
}
for i, c := range cs {
if c.IsLeaf() && c.Kind == views.STVert {
if i != len(cs)-1 {
for h := 0; h < c.H; h++ {
screen.SetContent(c.X+c.W, c.Y+h, divchar, combc, dividerStyle)
screen.SetContent(c.X+c.W, c.Y+h, '|', nil, dividerStyle.Reverse(true))
}
}
} else {

View File

@@ -1,7 +1,7 @@
package display
import (
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/internal/buffer"
)
type View struct {

View File

@@ -5,7 +5,7 @@ import (
"os"
"path/filepath"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/internal/config"
)
// LoadHistory attempts to load user history from configDir/buffers/history

View File

@@ -3,7 +3,7 @@ package info
import (
"fmt"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/internal/buffer"
)
// The InfoBuf displays messages and other info at the bottom of the screen.
@@ -146,7 +146,7 @@ func (i *InfoBuf) DonePrompt(canceled bool) {
h := i.History[i.PromptType]
h[len(h)-1] = resp
}
// i.PromptCallback = nil
i.PromptCallback = nil
}
i.Replace(i.Start(), i.End(), "")
}

View File

@@ -4,10 +4,9 @@ import (
"fmt"
"os"
"sync"
"unicode"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/internal/config"
"github.com/zyedidia/micro/internal/util"
"github.com/zyedidia/tcell"
)
@@ -98,10 +97,6 @@ func ShowCursor(x, y int) {
// SetContent sets a cell at a point on the screen and makes sure that it is
// synced with the last cursor location
func SetContent(x, y int, mainc rune, combc []rune, style tcell.Style) {
if !unicode.IsPrint(mainc) {
mainc = '<27>'
}
Screen.SetContent(x, y, mainc, combc, style)
if util.FakeCursor && lastCursor.x == x && lastCursor.y == y {
lastCursor.r = mainc
@@ -132,7 +127,7 @@ func TempStart(screenWasNil bool) {
// Init creates and initializes the tcell screen
func Init() {
drawChan = make(chan bool, 8)
drawChan = make(chan bool)
// Should we enable true color?
truecolor := os.Getenv("MICRO_TRUECOLOR") == "1"

View File

@@ -11,7 +11,7 @@ import (
"strings"
shellquote "github.com/kballard/go-shellquote"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/internal/screen"
)
// ExecCommand executes a command using exec

View File

@@ -5,8 +5,8 @@ import (
"os/exec"
"strconv"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/internal/buffer"
"github.com/zyedidia/micro/internal/screen"
"github.com/zyedidia/terminal"
)

View File

@@ -1,11 +1,15 @@
package util
import (
"unicode/utf8"
)
// LuaRuneAt is a helper function for lua plugins to return the rune
// at an index within a string
func LuaRuneAt(str string, runeidx int) string {
i := 0
for len(str) > 0 {
r, _, size := DecodeCharacterInString(str)
r, size := utf8.DecodeRuneInString(str)
str = str[size:]
@@ -22,7 +26,7 @@ func LuaRuneAt(str string, runeidx int) string {
func LuaGetLeadingWhitespace(s string) string {
ws := []byte{}
for len(s) > 0 {
r, _, size := DecodeCharacterInString(s)
r, size := utf8.DecodeRuneInString(s)
if r == ' ' || r == '\t' {
ws = append(ws, byte(r))
} else {
@@ -36,6 +40,6 @@ func LuaGetLeadingWhitespace(s string) string {
// LuaIsWordChar returns true if the first rune in a string is a word character
func LuaIsWordChar(s string) bool {
r, _, _ := DecodeCharacterInString(s)
r, _ := utf8.DecodeRuneInString(s)
return IsWordChar(r)
}

View File

@@ -1,86 +0,0 @@
package util
import (
"unicode"
"unicode/utf8"
)
// Unicode is annoying. A "code point" (rune in Go-speak) may need up to
// 4 bytes to represent it. In general, a code point will represent a
// complete character, but this is not always the case. A character with
// accents may be made up of multiple code points (the code point for the
// original character, and additional code points for each accent/marking).
// The functions below are meant to help deal with these additional "combining"
// code points. In underlying operations (search, replace, etc...), micro will
// treat a character with combining code points as just the original code point.
// For rendering, micro will display the combining characters. It's not perfect
// but it's pretty good.
// DecodeCharacter returns the next character from an array of bytes
// A character is a rune along with any accompanying combining runes
func DecodeCharacter(b []byte) (rune, []rune, int) {
r, size := utf8.DecodeRune(b)
b = b[size:]
c, s := utf8.DecodeRune(b)
var combc []rune
for unicode.In(c, unicode.Mark) {
combc = append(combc, c)
size += s
b = b[s:]
c, s = utf8.DecodeRune(b)
}
return r, combc, size
}
// DecodeCharacterInString returns the next character from a string
// A character is a rune along with any accompanying combining runes
func DecodeCharacterInString(str string) (rune, []rune, int) {
r, size := utf8.DecodeRuneInString(str)
str = str[size:]
c, s := utf8.DecodeRuneInString(str)
var combc []rune
for unicode.In(c, unicode.Mark) {
combc = append(combc, c)
size += s
str = str[s:]
c, s = utf8.DecodeRuneInString(str)
}
return r, combc, size
}
// CharacterCount returns the number of characters in a byte array
// Similar to utf8.RuneCount but for unicode characters
func CharacterCount(b []byte) int {
s := 0
for len(b) > 0 {
r, size := utf8.DecodeRune(b)
if !unicode.In(r, unicode.Mark) {
s++
}
b = b[size:]
}
return s
}
// CharacterCount returns the number of characters in a string
// Similar to utf8.RuneCountInString but for unicode characters
func CharacterCountInString(str string) int {
s := 0
for _, r := range str {
if !unicode.In(r, unicode.Mark) {
s++
}
}
return s
}

View File

@@ -1,7 +1,6 @@
package util
import (
"bytes"
"errors"
"fmt"
"os"
@@ -13,6 +12,7 @@ import (
"strings"
"time"
"unicode"
"unicode/utf8"
"github.com/blang/semver"
runewidth "github.com/mattn/go-runewidth"
@@ -30,13 +30,10 @@ var (
// CompileDate is the date this binary was compiled on
CompileDate = "Unknown"
// Debug logging
Debug = "OFF"
Debug = "ON"
// FakeCursor is used to disable the terminal cursor and have micro
// draw its own (enabled for windows consoles where the cursor is slow)
FakeCursor = false
// Stdout is a buffer that is written to stdout when micro closes
Stdout *bytes.Buffer
)
func init() {
@@ -49,7 +46,6 @@ func init() {
if runtime.GOOS == "windows" {
FakeCursor = true
}
Stdout = new(bytes.Buffer)
}
// SliceEnd returns a byte slice where the index is a rune index
@@ -63,7 +59,7 @@ func SliceEnd(slc []byte, index int) []byte {
return slc[totalSize:]
}
_, _, size := DecodeCharacter(slc[totalSize:])
_, size := utf8.DecodeRune(slc[totalSize:])
totalSize += size
i++
}
@@ -81,7 +77,7 @@ func SliceEndStr(str string, index int) string {
return str[totalSize:]
}
_, _, size := DecodeCharacterInString(str[totalSize:])
_, size := utf8.DecodeRuneInString(str[totalSize:])
totalSize += size
i++
}
@@ -100,7 +96,7 @@ func SliceStart(slc []byte, index int) []byte {
return slc[:totalSize]
}
_, _, size := DecodeCharacter(slc[totalSize:])
_, size := utf8.DecodeRune(slc[totalSize:])
totalSize += size
i++
}
@@ -118,7 +114,7 @@ func SliceStartStr(str string, index int) string {
return str[:totalSize]
}
_, _, size := DecodeCharacterInString(str[totalSize:])
_, size := utf8.DecodeRuneInString(str[totalSize:])
totalSize += size
i++
}
@@ -134,7 +130,7 @@ func SliceVisualEnd(b []byte, n, tabsize int) ([]byte, int, int) {
width := 0
i := 0
for len(b) > 0 {
r, _, size := DecodeCharacter(b)
r, size := utf8.DecodeRune(b)
w := 0
switch r {
@@ -171,7 +167,7 @@ func StringWidth(b []byte, n, tabsize int) int {
i := 0
width := 0
for len(b) > 0 {
r, _, size := DecodeCharacter(b)
r, size := utf8.DecodeRune(b)
b = b[size:]
switch r {
@@ -264,7 +260,7 @@ func IsBytesWhitespace(b []byte) bool {
// RunePos returns the rune index of a given byte index
// Make sure the byte index is not between code points
func RunePos(b []byte, i int) int {
return CharacterCount(b[:i])
return utf8.RuneCount(b[:i])
}
// MakeRelative will attempt to make a relative path between path and base
@@ -343,7 +339,7 @@ func EscapePath(path string) string {
func GetLeadingWhitespace(b []byte) []byte {
ws := []byte{}
for len(b) > 0 {
r, _, size := DecodeCharacter(b)
r, size := utf8.DecodeRune(b)
if r == ' ' || r == '\t' {
ws = append(ws, byte(r))
} else {
@@ -369,7 +365,7 @@ func GetCharPosInLine(b []byte, visualPos int, tabsize int) int {
i := 0 // char pos
width := 0 // string visual width
for len(b) > 0 {
r, _, size := DecodeCharacter(b)
r, size := utf8.DecodeRune(b)
b = b[size:]
switch r {
@@ -415,11 +411,7 @@ func Clamp(val, min, max int) int {
}
func IsNonAlphaNumeric(c rune) bool {
return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '_'
}
func IsAutocomplete(c rune) bool {
return c == '.' || !IsNonAlphaNumeric(c)
return !unicode.IsLetter(c) && !unicode.IsNumber(c)
}
func ParseSpecial(s string) string {

View File

@@ -3,6 +3,7 @@ package highlight
import (
"regexp"
"strings"
"unicode/utf8"
)
func sliceStart(slc []byte, index int) []byte {
@@ -14,7 +15,7 @@ func sliceStart(slc []byte, index int) []byte {
return slc[totalSize:]
}
_, _, size := DecodeCharacter(slc[totalSize:])
_, size := utf8.DecodeRune(slc[totalSize:])
totalSize += size
i++
}
@@ -31,7 +32,7 @@ func sliceEnd(slc []byte, index int) []byte {
return slc[:totalSize]
}
_, _, size := DecodeCharacter(slc[totalSize:])
_, size := utf8.DecodeRune(slc[totalSize:])
totalSize += size
i++
}
@@ -46,9 +47,9 @@ func runePos(p int, str []byte) int {
return 0
}
if p >= len(str) {
return CharacterCount(str)
return utf8.RuneCount(str)
}
return CharacterCount(str[:p])
return utf8.RuneCount(str[:p])
}
func combineLineMatch(src, dst LineMatch) LineMatch {
@@ -111,7 +112,7 @@ func findIndex(regex *regexp.Regexp, skip *regexp.Regexp, str []byte, canMatchSt
var strbytes []byte
if skip != nil {
strbytes = skip.ReplaceAllFunc(str, func(match []byte) []byte {
res := make([]byte, CharacterCount(match))
res := make([]byte, utf8.RuneCount(match))
return res
})
} else {
@@ -147,7 +148,7 @@ func findAllIndex(regex *regexp.Regexp, str []byte, canMatchStart, canMatchEnd b
}
func (h *Highlighter) highlightRegion(highlights LineMatch, start int, canMatchEnd bool, lineNum int, line []byte, curRegion *region, statesOnly bool) LineMatch {
lineLen := CharacterCount(line)
lineLen := utf8.RuneCount(line)
if start == 0 {
if !statesOnly {
if _, ok := highlights[0]; !ok {
@@ -235,7 +236,7 @@ func (h *Highlighter) highlightRegion(highlights LineMatch, start int, canMatchE
}
func (h *Highlighter) highlightEmptyRegion(highlights LineMatch, start int, canMatchEnd bool, lineNum int, line []byte, statesOnly bool) LineMatch {
lineLen := CharacterCount(line)
lineLen := utf8.RuneCount(line)
if lineLen == 0 {
if canMatchEnd {
h.lastRegion = nil
@@ -335,11 +336,11 @@ func (h *Highlighter) HighlightStates(input LineStates) {
}
}
// HighlightMatches sets the matches for each line from startline to endline
// HighlightMatches sets the matches for each line in between startline and endline
// It sets all other matches in the buffer to nil to conserve memory
// This assumes that all the states are set correctly
func (h *Highlighter) HighlightMatches(input LineStates, startline, endline int) {
for i := startline; i <= endline; i++ {
for i := startline; i < endline; i++ {
if i >= input.LinesNum() {
break
}

View File

@@ -1,75 +0,0 @@
package highlight
import (
"unicode"
"unicode/utf8"
)
// DecodeCharacter returns the next character from an array of bytes
// A character is a rune along with any accompanying combining runes
func DecodeCharacter(b []byte) (rune, []rune, int) {
r, size := utf8.DecodeRune(b)
b = b[size:]
c, s := utf8.DecodeRune(b)
var combc []rune
for unicode.In(c, unicode.Mark) {
combc = append(combc, c)
size += s
b = b[s:]
c, s = utf8.DecodeRune(b)
}
return r, combc, size
}
// DecodeCharacterInString returns the next character from a string
// A character is a rune along with any accompanying combining runes
func DecodeCharacterInString(str string) (rune, []rune, int) {
r, size := utf8.DecodeRuneInString(str)
str = str[size:]
c, s := utf8.DecodeRuneInString(str)
var combc []rune
for unicode.In(c, unicode.Mark) {
combc = append(combc, c)
size += s
str = str[s:]
c, s = utf8.DecodeRuneInString(str)
}
return r, combc, size
}
// CharacterCount returns the number of characters in a byte array
// Similar to utf8.RuneCount but for unicode characters
func CharacterCount(b []byte) int {
s := 0
for len(b) > 0 {
r, size := utf8.DecodeRune(b)
if !unicode.In(r, unicode.Mark) {
s++
}
b = b[size:]
}
return s
}
// CharacterCount returns the number of characters in a string
// Similar to utf8.RuneCountInString but for unicode characters
func CharacterCountInString(str string) int {
s := 0
for _, r := range str {
if !unicode.In(r, unicode.Mark) {
s++
}
}
return s
}

View File

@@ -1,34 +0,0 @@
color-link color-column "#001e28"
color-link comment "#608b4e,#001e28"
color-link constant.bool "#fd971f,#001e28"
color-link constant "#fd971f,#001e28"
color-link constant.string "#a0f000,#001e28"
color-link constant.string.char "#a0f000,#001e28"
color-link constant.string.url "#a0f000,#001e28"
color-link current-line-number "bold #fd971f,#001e28"
color-link cursor-line "#001923"
color-link default "#ffffff,#001e28"
color-link diff-added "#00c8a0,#001e28"
color-link diff-modified "#fd971f,#001e28"
color-link diff-deleted "#cb4b16,#001e28"
color-link divider "#001e28,#d0d0d0"
color-link error "#cb4b16,#001e28"
color-link gutter-error "#cb4b16,#001e28"
color-link gutter-warning "#fce94f,#001e28"
color-link identifier "#00c8a0,#001e28"
color-link identifier.class "#00c8a0,#001e28"
color-link indent-char "#a0a0a0,#001e28"
color-link line-number "#a0a0a0,#001923"
color-link preproc "bold #5aaae6,#001e28"
color-link special "#a6e22e,#001e28"
color-link statement "bold #5aaae6,#001e28"
color-link statusline "#ffffff,#0078c8"
color-link symbol "#00c8a0,#001e28"
color-link symbol.brackets "#ffffff,#001e28"
color-link symbol.tag "bold #5aaae6,#001e28"
color-link tabbar "#001e28,#ffffff"
color-link todo "#fce94f,#001e28"
color-link type "bold #3cc83c,#001e28"
color-link type.keyword "bold #5aaae6,#001e28"
color-link type.extended "#ffffff,#001e28"
color-link underlined "#608b4e,#001e28"

View File

@@ -1,34 +0,0 @@
color-link color-column "#f0f0f0"
color-link comment "#3f7f5f,#f0f0f0"
color-link constant.bool "#641e00,#f0f0f0"
color-link constant "#641e00,#f0f0f0"
color-link constant.string "#0000ff,#f0f0f0"
color-link constant.string.char "#0000ff,#f0f0f0"
color-link constant.string.url "#0000ff,#f0f0f0"
color-link current-line-number "bold #004080,#f0f0f0"
color-link cursor-line "#e6e6e6"
color-link default "#000000,#f0f0f0"
color-link diff-added "#008040,#f0f0f0"
color-link diff-modified "#641e00,#f0f0f0"
color-link diff-deleted "#500000,#f0f0f0"
color-link divider "#f0f0f0,#004080"
color-link error "#500000,#f0f0f0"
color-link gutter-error "#500000,#f0f0f0"
color-link gutter-warning "#dcc800,#f0f0f0"
color-link identifier "bold #0078a0,#f0f0f0"
color-link identifier.class "bold #0078a0,#f0f0f0"
color-link indent-char "#404040,#f0f0f0"
color-link line-number "#404040,#e6e6e6"
color-link preproc "bold #780050,#f0f0f0"
color-link special "bold #0078a0,#f0f0f0"
color-link statement "bold #780050,#f0f0f0"
color-link statusline "#ffffff,#0078c8"
color-link symbol "bold #0078a0,#f0f0f0"
color-link symbol.brackets "#000000,#f0f0f0"
color-link symbol.tag "bold #780050,#f0f0f0"
color-link tabbar "#f0f0f0,#004080"
color-link todo "#dcc800,#f0f0f0"
color-link type "bold #004080,#f0f0f0"
color-link type.keyword "bold #780050,#f0f0f0"
color-link type.extended "#000000,#f0f0f0"
color-link underlined "#3f7f5f,#f0f0f0"

View File

@@ -1,34 +0,0 @@
color-link color-column "#2d0023"
color-link comment "#886484,#2d0023"
color-link constant.bool "#fd971f,#2d0023"
color-link constant "#fd971f,#2d0023"
color-link constant.string "#a0f000,#2d0023"
color-link constant.string.char "#a0f000,#2d0023"
color-link constant.string.url "#a0f000,#2d0023"
color-link current-line-number "bold #fd971f,#2d0023"
color-link cursor-line "#230019"
color-link default "#ffffff,#2d0023"
color-link diff-added "#00c8a0,#2d0023"
color-link diff-modified "#fd971f,#2d0023"
color-link diff-deleted "#cb4b16,#2d0023"
color-link divider "#2d0023,#d0d0d0"
color-link error "#cb4b16,#2d0023"
color-link gutter-error "#cb4b16,#2d0023"
color-link gutter-warning "#fce94f,#2d0023"
color-link identifier "#00c8a0,#2d0023"
color-link identifier.class "#00c8a0,#2d0023"
color-link indent-char "#a0a0a0,#2d0023"
color-link line-number "#a0a0a0,#230019"
color-link preproc "bold #5aaae6,#2d0023"
color-link special "#a6e22e,#2d0023"
color-link statement "bold #5aaae6,#2d0023"
color-link statusline "#ffffff,#0078c8"
color-link symbol "#00c8a0,#2d0023"
color-link symbol.brackets "#ffffff,#2d0023"
color-link symbol.tag "bold #5aaae6,#2d0023"
color-link tabbar "#2d0023,#ffffff"
color-link todo "#fce94f,#2d0023"
color-link type "bold #3cc83c,#2d0023"
color-link type.keyword "bold #5aaae6,#2d0023"
color-link type.extended "#ffffff,#2d0023"
color-link underlined "#886484,#2d0023"

View File

@@ -11,7 +11,7 @@ color-link todo "bold #cc7833,#2b2b2b"
color-link error "bold #cc7833,#2b2b2b"
color-link gutter-error "#cc7833,#11151C"
color-link indent-char "#414141,#2b2b2b"
color-link line-number "#a1a1a1,#232323"
color-link line-number "#a1a1a1,#353535"
color-link current-line-number "#e6e1dc,#2b2b2b"
color-link diff-added "#00AF00"
color-link diff-modified "#FFAF00"
@@ -19,8 +19,8 @@ color-link diff-deleted "#D70000"
color-link gutter-warning "#a5c261,#11151C"
color-link symbol "#edb753,#2b2b2b"
color-link identifier "#edb753,#2b2b2b"
color-link statusline "#b1b1b1,#232323"
color-link tabbar "bold #b1b1b1,#232323"
color-link statusline "#a1a1a1,#414141"
color-link tabbar "bold #a1a1a1,#414141"
color-link cursor-line "#353535"
color-link color-column "#353535"
color-link space "underline #e6e1dc,#2b2b2b"

View File

@@ -132,7 +132,7 @@ If you would like no foreground you can just use a comma with nothing in front:
color-link comment ",blue"
```
You can also put bold, italic, or underline in front of the color:
You can also put bold, or underline in front of the color:
```
color-link comment "bold red"

View File

@@ -62,11 +62,6 @@ quotes here but these are not necessary when entering the command in micro.
* `tab 'filename'`: opens the given file in a new tab.
* `tabmove '[-+]?n'`: Moves the active tab to another slot. `n` is an integer.
If `n` is prefixed with `-` or `+`, then it represents a relative position
(e.g. `tabmove +2` moves the tab to the right by `2`). If `n` has no prefix,
it represents an absolute position (e.g. `tabmove 2` moves the tab to slot `2`).
* `tabswitch 'tab'`: This command will switch to the specified tab. The `tab`
can either be a tab number, or a name of a tab.

View File

@@ -23,7 +23,7 @@ can change it!
| Shift+arrows | Move and select text |
| Alt(Ctrl on Mac)+LeftArrow | Move to the beginning of the current line |
| Alt(Ctrl on Mac)+RightArrow | Move to the end of the current line |
| Home | Move to the beginning of text on the current line |
| Home | Move to the beginning of the current line |
| End | Move to the end of the current line |
| Ctrl(Alt on Mac)+LeftArrow | Move cursor one word left |
| Ctrl(Alt on Mac)+RightArrow | Move cursor one word right |

View File

@@ -162,8 +162,6 @@ SelectUp
SelectDown
SelectLeft
SelectRight
SelectToStartOfText
SelectToStartOfTextToggle
WordRight
WordLeft
SelectWordRight
@@ -185,13 +183,11 @@ Save
SaveAll
SaveAs
Find
FindLiteral
FindNext
FindPrevious
Undo
Redo
Copy
CopyLine
Cut
CutLine
DuplicateLine
@@ -213,8 +209,6 @@ HalfPageUp
HalfPageDown
StartOfLine
EndOfLine
StartOfText
StartOfTextToggle
ParagraphPrevious
ParagraphNext
ToggleHelp
@@ -251,9 +245,6 @@ JumpToMatchingBrace
Autocomplete
```
The `StartOfTextToggle` and `SelectToStartOfTextToggle` actions toggle between
jumping to the start of the text (first) and start of the line.
You can also bind some mouse actions (these must be bound to mouse buttons)
```
@@ -419,21 +410,21 @@ conventions for text editing defaults.
"ShiftDown": "SelectDown",
"ShiftLeft": "SelectLeft",
"ShiftRight": "SelectRight",
"AltLeft": "WordLeft", (Mac)
"AltRight": "WordRight", (Mac)
"AltLeft": "WordLeft",
"AltRight": "WordRight",
"AltUp": "MoveLinesUp",
"AltDown": "MoveLinesDown",
"CtrlShiftRight": "SelectWordRight",
"CtrlShiftLeft": "SelectWordLeft",
"AltLeft": "StartOfTextToggle",
"AltLeft": "StartOfLine",
"AltRight": "EndOfLine",
"AltShiftRight": "SelectWordRight", (Mac)
"AltShiftLeft": "SelectWordLeft", (Mac)
"CtrlLeft": "StartOfText", (Mac)
"CtrlRight": "EndOfLine", (Mac)
"AltShiftLeft": "SelectToStartOfTextToggle",
"CtrlShiftLeft": "SelectToStartOfTextToggle", (Mac)
"ShiftHome": "SelectToStartOfTextToggle",
"AltShiftLeft": "SelectToStartOfLine",
"CtrlShiftLeft": "SelectToStartOfText", (Mac)
"ShiftHome": "SelectToStartOfLine",
"AltShiftRight": "SelectToEndOfLine",
"CtrlShiftRight": "SelectToEndOfLine", (Mac)
"ShiftEnd": "SelectToEndOfLine",
@@ -457,7 +448,7 @@ conventions for text editing defaults.
"CtrlP": "FindPrevious",
"CtrlZ": "Undo",
"CtrlY": "Redo",
"CtrlC": "CopyLine|Copy",
"CtrlC": "Copy",
"CtrlX": "Cut",
"CtrlK": "CutLine",
"CtrlD": "DuplicateLine",
@@ -466,7 +457,7 @@ conventions for text editing defaults.
"CtrlT": "AddTab",
"Alt,": "PreviousTab",
"Alt.": "NextTab",
"Home": "StartOfText",
"Home": "StartOfLine",
"End": "EndOfLine",
"CtrlHome": "CursorStart",
"CtrlEnd": "CursorEnd",

View File

@@ -44,8 +44,8 @@ Here are the available options:
default value: `true`
* `basename`: in the infobar and tabbar, show only the basename of the file
being edited rather than the full path.
* `basename`: in the infobar, show only the basename of the file being edited
rather than the full path.
default value: `false`
@@ -80,30 +80,14 @@ Here are the available options:
default value: `false`
* `divchars`: specifies the "divider" characters used for the dividing line
between vertical/horizontal splits. The first character is for vertical
dividers, and the second is for horizontal dividers. By default, for
horizontal splits the statusline serves as a divider, but if the statusline
is disabled the horizontal divider character will be used.
default value: `|-`
* `divreverse`: colorschemes provide the color (foreground and background) for
the characters displayed in split dividers. With this option enabled, the
colors specified by the colorscheme will be reversed (foreground and
background colors swapped).
default value: `true`
* `encoding`: the encoding to open and save files with. Supported encodings
are listed at https://www.w3.org/TR/encoding/.
default value: `utf-8`
* `eofnewline`: micro will automatically add a newline to the end of the
file if one does not exist.
* `eofnewline`: micro will automatically add a newline to the file.
default value: `true`
default value: `false`
* `fastdirty`: this determines what kind of algorithm micro uses to determine
if a buffer is modified or not. When `fastdirty` is on, micro just uses a
@@ -117,15 +101,12 @@ Here are the available options:
default value: `false`
* `fileformat`: this determines what kind of line endings micro will use for
the file. Unix line endings are just `\n` (linefeed) whereas dos line
the file. UNIX line endings are just `\n` (linefeed) whereas dos line
endings are `\r\n` (carriage return + linefeed). The two possible values for
this option are `unix` and `dos`. The fileformat will be automatically
detected (when you open an existing file) and displayed on the statusline,
but this option is useful if you would like to change the line endings or if
you are starting a new file. Changing this option while editing a file will
change its line endings. Opening a file with this option set will only have
an effect if the file is empty/newly created, because otherwise the fileformat
will be automatically detected from the existing line endings.
you are starting a new file.
default value: `unix`
@@ -181,7 +162,7 @@ Here are the available options:
default value: `true`
* `paste`: treat characters sent from the terminal in a single chunk as a paste
* `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
@@ -190,16 +171,6 @@ Here are the available options:
default value: `false`
* `parsecursor`: if enabled, this will cause micro to parse filenames such as
file.txt:10:5 as requesting to open `file.txt` with the cursor at line 10
and column 5. The column number can also be dropped to open the file at a
given line and column 0. Note that with this option enabled it is not possible
to open a file such as `file.txt:10:5`, where `:10:5` is part of the filename.
It is also possible to open a file with a certain cursor location by using the
`+LINE,COL` flag syntax. See `micro -help` for the command line options.
default value: `false`
* `pluginchannels`: list of URLs pointing to plugin channels for downloading and
installing plugins. A plugin channel consists of a json file with links to
plugin repos, which store information about plugin versions and download URLs.
@@ -227,12 +198,6 @@ Here are the available options:
default value: `true`
* `relativeruler`: make line numbers display relatively. If set to true, all lines except
for the line that the cursor is located will display the distance from the
cursor's line.
default value: `false`
* `savecursor`: remember where the cursor was last time the file was opened and
put it there when you open the file again. Information is saved to
`~/.config/micro/buffers/`

View File

@@ -28,7 +28,7 @@ function onRune(bp, r)
if r == charAt(autoclosePairs[i], 1) then
local curLine = bp.Buf:Line(bp.Cursor.Y)
if bp.Cursor.X == uutil.CharacterCountInString(curLine) or not uutil.IsWordChar(charAt(curLine, bp.Cursor.X+1)) then
if bp.Cursor.X == utf8.RuneCountInString(curLine) or not uutil.IsWordChar(charAt(curLine, bp.Cursor.X+1)) then
-- the '-' here is to derefence the pointer to bp.Cursor.Loc which is automatically made
-- when converting go structs to lua
-- It needs to be dereferenced because the function expects a non pointer struct

View File

@@ -23,7 +23,6 @@ ft["javascript"] = "// %s"
ft["ruby"] = "# %s"
ft["d"] = "// %s"
ft["swift"] = "// %s"
ft["elm"] = "-- %s"
function onBufferOpen(buf)
if buf.Settings["commenttype"] == nil then

View File

@@ -6,8 +6,6 @@ local filepath = import("path/filepath")
local shell = import("micro/shell")
local buffer = import("micro/buffer")
local config = import("micro/config")
local util = import("micro/util")
local os = import("os")
local linters = {}
@@ -66,11 +64,10 @@ function init()
end
makeLinter("gcc", "c", "gcc", {"-fsyntax-only", "-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m")
makeLinter("g++", "c++", "gcc", {"-fsyntax-only","-std=c++14", "-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m")
makeLinter("gcc", "c++", "gcc", {"-fsyntax-only","-std=c++14", "-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m")
makeLinter("dmd", "d", "dmd", {"-color=off", "-o-", "-w", "-wi", "-c", "%f"}, "%f%(%l%):.+: %m")
makeLinter("gobuild", "go", "go", {"build", "-o", devnull, "%d"}, "%f:%l:%c:? %m")
makeLinter("gobuild", "go", "go", {"build", "-o", devnull}, "%f:%l:%c:? %m")
-- makeLinter("golint", "go", "golint", {"%f"}, "%f:%l:%c: %m")
makeLinter("hlint", "haskell", "hlint", {"%f"}, "%f:%l:%c.-: %m")
makeLinter("javac", "java", "javac", {"-d", "%d", "%f"}, "%f:%l: error: %m")
makeLinter("jshint", "javascript", "jshint", {"%f"}, "%f: line %l,.+, %m")
makeLinter("literate", "literate", "lit", {"-c", "%f"}, "%f:%l:%m", {}, false, true)
@@ -105,7 +102,7 @@ end
function runLinter(buf)
local ft = buf:FileType()
local file = buf.Path
local dir = "." .. util.RuneStr(os.PathSeparator) .. filepath.Dir(file)
local dir = filepath.Dir(file)
for k, v in pairs(linters) do
local ftmatch = ft == v.filetype

28
runtime/syntax/c++.yaml Normal file
View File

@@ -0,0 +1,28 @@
filetype: c++
detect:
filename: "\\.c(c|pp|xx)$|\\.h(h|pp|xx)$|\\.ii?$|\\.(def)$"
rules:
- identifier: "\\b[A-Z_][0-9A-Z_]+\\b"
- type: "\\b(auto|float|double|bool|char|int|short|long|sizeof|enum|void|static|const|constexpr|struct|union|typedef|extern|(un)?signed|inline)\\b"
- type: "\\b((s?size)|((u_?)?int(8|16|32|64|ptr)))_t\\b"
- statement: "\\b(class|namespace|template|public|protected|private|typename|this|friend|virtual|using|mutable|volatile|register|explicit)\\b"
- statement: "\\b(for|if|while|do|else|case|default|switch)\\b"
- statement: "\\b(try|throw|catch|operator|new|delete)\\b"
- special: "\\b(goto|continue|break|return)\\b"
- preproc: "^[[:space:]]*#[[:space:]]*(define|pragma|include|(un|ifn?)def|endif|el(if|se)|if|warning|error)"
- constant: "'([^'\\\\]|(\\\\[\"'abfnrtv\\\\]))'|'\\\\(([0-3]?[0-7]{1,2}))'|'\\\\x[0-9A-Fa-f]{1,2}'"
- statement: "__attribute__[[:space:]]*\\(\\([^)]*\\)\\)|__(aligned|asm|builtin|hidden|inline|packed|restrict|section|typeof|weak)__"
- symbol.operator: "[.:;,+*|=!\\%]|<|>|/|-|&"
- symbol.brackets: "[(){}]|\\[|\\]"
- constant.number: "\\b[0-9]+\\b|\\b0x[0-9A-Fa-f]+\\b"
- constant.bool: "\\b(true|false)\\b|NULL"
- constant.string: "\"(\\\\.|[^\"])*\""
- comment: "//.*"
- comment:
start: "/\\*"
end: "\\*/"
rules: []
- indent-char.whitespace: "[[:space:]]+$"

View File

@@ -12,9 +12,6 @@ rules:
- statement: "\\b(debugger|switch|while|do|class|extends|super)\\b"
- statement: "\\b(undefined|then|unless|until|loop|of|by|when)\\b"
- constant.bool: "\\b(true|false|yes|no|on|off)\\b"
- constant.number: "\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\\b"
- constant.number: "\\b[-+]?([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+)([EePp][+-]?[0-9]+)?[fFlL]?"
- constant.number: "\\b[-+]?([0-9]+[EePp][+-]?[0-9]+)[fFlL]?"
- identifier: "@[A-Za-z0-9_]*"
- constant.string:
@@ -23,23 +20,10 @@ rules:
skip: "\\\\."
rules:
- constant.specialChar: "\\\\."
- constant.string:
start: "'"
end: "'"
skip: "\\\\."
rules:
- constant.specialChar: "\\\\."
- comment:
start: "#"
end: "$"
rules:
- todo: "(TODO|XXX|FIXME):?"
- comment:
start: "###"
end: "###"
rules:
- todo: "(TODO|XXX|FIXME)"

View File

@@ -1,8 +0,0 @@
filetype: csharp-script
detect:
filename: "\\.csx$"
header: "^#!.*/(env +)?dotnet-script( |$)"
rules:
- include: "csharp"
- preproc: "\\B(\\#!|\\#[r|load|]+\\b)"

View File

@@ -26,7 +26,7 @@ rules:
# Diffs (i.e. git commit --verbose)
- default:
start: "^diff --git"
start: "^diff"
# Diff output puts a space before file contents on each line so this
# should never match valid diff output and extend highlighting to the
# end of the file

View File

@@ -8,14 +8,13 @@ rules:
# built-in objects
- constant.bool: "\\b(true|false)\\b"
- constant: "\\b(nothing|missing)\\b"
# built-in attributes
- constant: "__[A-Za-z0-9_]+__"
# definitions
- identifier: "[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[(]"
# keywords
- statement: "\\b(baremodule|begin|break|catch|const|continue|do|else|elseif|end|export|finally|for|function|global|if|import|let|local|macro|module|quote|return|struct|try|using|while)\\b"
- statement: "\\b(abstract\\s+type|primitive\\s+type|mutable\\s+struct)\\b"
- statement: "\\b(abstract type|primitive type|mutable struct\\b)"
# decorators
- identifier.macro: "@[A-Za-z0-9_]+"
# operators
@@ -23,7 +22,7 @@ rules:
# parentheses
- symbol.brackets: "([(){}]|\\[|\\])"
# numbers
- constant.number: "\\b([0-9]+(_[0-9]+)*|0x[0-9a-fA-F]+(_[0-9a-fA-F]+)*|0b[01]+(_[01]+)*|0o[0-7]+(_[0-7]+)*|Inf(16|32|64)?|NaN(16|32|64)?)\\b"
- constant.number: "\\b([0-9]+(_[0-9]+)*|0x[0-9a-fA-F]+(_[0-9a-fA-F]+)*|0b[01]+(_[01]+)*|0o[0-7]+(_[0-7]+)*)\\b"
- constant.string: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^']){1}'"

View File

@@ -1,8 +1,8 @@
filetype: python2
filetype: python
detect:
filename: "\\.py2$"
header: "^#!.*/(env +)?python2$"
filename: "\\.py$"
header: "^#!.*/(env +)?python( |$)"
rules:

View File

@@ -1,8 +1,8 @@
filetype: python
filename: python3
detect:
filename: "\\.py(3)?$"
header: "^#!.*/(env +)?python(3)?$"
filename: "\\.py3$"
header: "^#!.*/(env +)?python3$"
rules:
# built-in objects
@@ -18,7 +18,7 @@ rules:
# definitions
- identifier: "def [a-zA-Z_0-9]+"
# keywords
- statement: "\\b(and|as|assert|async|await|break|class|continue|def|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|raise|return|try|while|with|yield)\\b"
- statement: "\\b(and|as|assert|await|break|class|continue|def|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|raise|return|try|while|with|yield)\\b"
# decorators
- brightgreen: "@.*[(]"
# operators

View File

@@ -1,7 +1,7 @@
filetype: ruby
detect:
filename: "\\.(rb|rake|gemspec)$|^(Gemfile|config.ru|Rakefile|Capfile|Vagrantfile|Guardfile|Appfile|Fastfile|Pluginfile|Podfile)$"
filename: "\\.(rb|rake|gemspec)$|^(Gemfile|config.ru|Rakefile|Capfile|Vagrantfile|Guardfile)$"
header: "^#!.*/(env +)?ruby( |$)"
rules:

View File

@@ -1,60 +0,0 @@
filetype: sage
detect:
filename: "\\.sage$"
header: "^#!.*/(env +)?sage( |$)"
rules:
# built-in objects
- constant: "\\b(None|self|True|False)\\b"
# built-in attributes
- constant: "\\b(__bases__|__builtin__|__class__|__debug__|__dict__|__doc__|__file__|__members__|__methods__|__name__|__self__)\\b"
# built-in functions
- identifier: "\\b(abs|apply|callable|chr|cmp|compile|delattr|dir|divmod|eval|exec|execfile|filter|format|getattr|globals|hasattr|hash|help|hex|id|input|intern|isinstance|issubclass|len|locals|max|min|next|oct|open|ord|pow|range|raw_input|reduce|reload|repr|round|setattr|unichr|vars|zip|__import__)\\b"
# special method names
- identifier: "\\b(__abs__|__add__|__and__|__call__|__cmp__|__coerce__|__complex__|__concat__|__contains__|__del__|__delattr__|__delitem__|__dict__|__delslice__|__div__|__divmod__|__float__|__getattr__|__getitem__|__getslice__|__hash__|__hex__|__init__|__int__|__inv__|__invert__|__len__|__long__|__lshift__|__mod__|__mul__|__neg__|__nonzero__|__oct__|__or__|__pos__|__pow__|__radd__|__rand__|__rcmp__|__rdiv__|__rdivmod__|__repeat__|__repr__|__rlshift__|__rmod__|__rmul__|__ror__|__rpow__|__rrshift__|__rshift__|__rsub__|__rxor__|__setattr__|__setitem__|__setslice__|__str__|__sub__|__xor__)\\b"
# types
- type: "\\b(basestring|bool|buffer|bytearray|bytes|classmethod|complex|dict|enumerate|file|float|frozenset|int|list|long|map|memoryview|object|property|reversed|set|slice|staticmethod|str|super|tuple|type|unicode|xrange)\\b"
# definitions
- identifier: "def [a-zA-Z_0-9]+"
# keywords
- statement: "\\b(and|as|assert|break|class|continue|def|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|not|or|pass|print|raise|return|try|while|with|yield)\\b"
# decorators
- brightgreen: "@.*[(]"
# operators
- statement: "([.:;,+*|=!\\%@]|<|>|/|-|&)"
# parentheses
- statement: "([(){}]|\\[|\\])"
# numbers
- constant.number: "\\b[0-9]+\\b"
- comment:
start: "\"\"\""
end: "\"\"\""
rules: []
- comment:
start: "'''"
end: "'''"
rules: []
- constant.string:
start: "\""
end: "\""
skip: "\\\\."
rules:
- constant.specialChar: "\\\\."
- constant.string:
start: "'"
end: "'"
skip: "\\\\."
rules:
- constant.specialChar: "\\\\."
- comment:
start: "#"
end: "$"
rules: []

View File

@@ -1,8 +1,8 @@
filetype: shell
detect:
filename: "(\\.sh$|\\.bash|\\.ash|bashrc|bash_aliases|bash_functions|profile|bash-fc\\.|Pkgfile|pkgmk.conf|rc.conf|PKGBUILD|.ebuild\\$|APKBUILD)"
header: "^#!.*/(env +)?(ba)?(a)?(mk)?sh( |$)"
filename: "(\\.sh$|\\.bash|\\.ash|\\.bashrc|bashrc|\\.bash_aliases|bash_aliases|\\.bash_functions|bash_functions|\\.bash_profile|bash_profile|\\.profile|profile|Pkgfile|pkgmk.conf|profile|rc.conf|PKGBUILD|.ebuild\\$|APKBUILD)"
header: "^#!.*/(env +)?(ba)?(a)?sh( |$)"
rules:
# Numbers

View File

@@ -4,53 +4,39 @@ detect:
filename: "\\.toml"
rules:
# Punctuation
- symbol: '[=,\.]'
- symbol.brackets: '[{\[\]}]'
# Strings
- statement: "(.*)[[:space:]]="
- special: "="
# Bracket thingies
- special: "(\\[|\\])"
# Numbers and strings
- constant.number: "\\b([0-9]+|0x[0-9a-fA-F]*)\\b|'.'"
- constant.number: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})"
- constant.string:
start: '"""'
end: '\"{3,5}'
skip: '\\.'
start: "\""
end: "\""
skip: "\\\\."
rules:
- constant.specialChar: '\\u[[:xdigit:]]{4}'
- constant.specialChar: '\\U[[:xdigit:]]{8}'
- constant.specialChar: '\\[btnfr"\\]'
- constant.string:
start: '"'
end: '"'
skip: '\\.'
rules:
- constant.specialChar: '\\u[[:xdigit:]]{4}'
- constant.specialChar: '\\U[[:xdigit:]]{8}'
- constant.specialChar: '\\[btnfr"\\]'
- constant.string:
start: "'''"
end: "'{3,5}"
rules: []
- constant.specialChar: "\\\\."
- constant.string:
start: "'"
end: "'"
rules: []
# Integer
- constant.number: '[+-]?(\d+_)*\d+\b'
- constant.number: '(0x([[:xdigit:]]+_)*[[:xdigit:]]+|0o([0-7]_)*[0-7]+|0b([01]+_)*[01]+)'
# Float
- constant.number: '[+-]?(\d+_)*\d+\.(\d+_)*\d+'
- constant.number: '[+-]?(\d+_)*\d+(\.(\d+_)*\d+)?[Ee][+-]?(\d+_)*\d+'
- constant.number: '(\+|-)(inf|nan)'
# Bare key, keys starting with a digit or dash are ambiguous with numbers and are skipped
- identifier: '\b[A-Za-z_][A-Za-z0-9_-]*\b'
# Boolean and inf, nan without sign
- constant.bool.true: '\btrue\b'
- constant.bool.false: '\bfalse\b'
- constant.number: '\b(inf|nan)\b'
# Date and Time
- constant: '\d+-\d{2}-\d{2}([T ]\d{2}:\d{2}:\d{2}(\.\d+)?([+-]\d{2}:\d{2}|Z)?)?'
- constant: '\d{2}:\d{2}:\d{2}(\.\d+)?'
# Comments
skip: "\\\\."
rules:
- constant.specialChar: "\\\\."
- constant.string:
start: "`"
end: "`"
rules:
- constant.specialChar: "\\\\."
- comment:
start: "#"
end: "$"
rules:
- todo: "(TODO|XXX|FIXME):?"

View File

@@ -53,7 +53,7 @@ func main() {
}
// If we don't have any tag assume "dev"
if tag == "" || strings.HasPrefix(tag, "nightly") {
if tag == "" {
tag = "dev"
}
// Get the most likely next version:

View File

@@ -1,5 +1,5 @@
# This script creates the nightly release on Github for micro
# You must have the correct Github access token to run this script
# Must be run from inside the micro git repository
commitID=$(git rev-parse HEAD)
info=$(github-release info -u zyedidia -r micro -t nightly)
@@ -10,152 +10,32 @@ if [[ $info = *$commitID* ]]; then
fi
echo "Deleting old release"
github-release delete \
--user zyedidia \
--repo micro \
--tag nightly
hub release delete nightly
echo "Moving tag"
git tag --force nightly $commitID
git push --force --tags
echo "Creating new release"
github-release release \
--user zyedidia \
--repo micro \
--tag nightly \
--name "Nightly build" \
--description "Autogenerated nightly build of micro. If you don't see anything here that probably means it's building right now!" \
--pre-release
hub push origin :refs/tags/nightly
git tag -f nightly $commitID
hub push --tags
echo "Cross compiling binaries"
./cross-compile.sh $1
mv ../binaries .
echo "Uploading OSX binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag nightly \
--name "micro-$1-osx.tar.gz" \
--file binaries/micro-$1-osx.tar.gz
echo "Uploading Linux 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag nightly \
--name "micro-$1-linux64.tar.gz" \
--file binaries/micro-$1-linux64.tar.gz
echo "Uploading Linux 64 static binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag nightly \
--name "micro-$1-linux64-static.tar.gz" \
--file binaries/micro-$1-linux64-static.tar.gz
echo "Uploading Linux 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag nightly \
--name "micro-$1-linux32.tar.gz" \
--file binaries/micro-$1-linux32.tar.gz
echo "Uploading Linux Arm 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag nightly \
--name "micro-$1-linux-arm.tar.gz" \
--file binaries/micro-$1-linux-arm.tar.gz
echo "Uploading Linux Arm 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag nightly \
--name "micro-$1-linux-arm64.tar.gz" \
--file binaries/micro-$1-linux-arm64.tar.gz
echo "Uploading FreeBSD 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag nightly \
--name "micro-$1-freebsd64.tar.gz" \
--file binaries/micro-$1-freebsd64.tar.gz
echo "Uploading FreeBSD 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag nightly \
--name "micro-$1-freebsd32.tar.gz" \
--file binaries/micro-$1-freebsd32.tar.gz
echo "Uploading OpenBSD 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag nightly \
--name "micro-$1-openbsd64.tar.gz" \
--file binaries/micro-$1-openbsd64.tar.gz
echo "Uploading OpenBSD 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag nightly \
--name "micro-$1-openbsd32.tar.gz" \
--file binaries/micro-$1-openbsd32.tar.gz
echo "Uploading NetBSD 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag nightly \
--name "micro-$1-netbsd64.tar.gz" \
--file binaries/micro-$1-netbsd64.tar.gz
echo "Uploading NetBSD 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag nightly \
--name "micro-$1-netbsd32.tar.gz" \
--file binaries/micro-$1-netbsd32.tar.gz
echo "Uploading Windows 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag nightly \
--name "micro-$1-win64.zip" \
--file binaries/micro-$1-win64.zip
echo "Uploading Windows 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag nightly \
--name "micro-$1-win32.zip" \
--file binaries/micro-$1-win32.zip
# echo "Uploading vendored tarball"
# github-release upload \
# --user zyedidia \
# --repo micro \
# --tag nightly \
# --name "micro-$1-src.tar.gz" \
# --file binaries/micro-$1-src.tar.gz
#
# echo "Uploading vendored zip"
# github-release upload \
# --user zyedidia \
# --repo micro \
# --tag nightly \
# --name "micro-$1-src.zip" \
# --file binaries/micro-$1-src.zip
echo "Creating new release"
hub release create nightly \
--prerelease \
--message $'Nightly build\n\nAutogenerated nightly build of micro.' \
--attach "binaries/micro-$1-osx.tar.gz" \
--attach "binaries/micro-$1-linux64.tar.gz" \
--attach "binaries/micro-$1-linux64-static.tar.gz" \
--attach "binaries/micro-$1-linux32.tar.gz" \
--attach "binaries/micro-$1-linux-arm.tar.gz" \
--attach "binaries/micro-$1-linux-arm64.tar.gz" \
--attach "binaries/micro-$1-freebsd64.tar.gz" \
--attach "binaries/micro-$1-freebsd32.tar.gz" \
--attach "binaries/micro-$1-openbsd64.tar.gz" \
--attach "binaries/micro-$1-openbsd32.tar.gz" \
--attach "binaries/micro-$1-netbsd64.tar.gz" \
--attach "binaries/micro-$1-netbsd32.tar.gz" \
--attach "binaries/micro-$1-win64.zip" \
--attach "binaries/micro-$1-win32.zip"

View File

@@ -8,145 +8,29 @@ tag="v$1"
echo "Creating tag"
git tag $tag $commitID
git push --tags
echo "Creating new release"
github-release release \
--user zyedidia \
--repo micro \
--tag $tag \
--name "$1" \
--description "$2" \
--pre-release
hub push --tags
echo "Cross compiling binaries"
./cross-compile.sh $1
mv ../binaries .
echo "Uploading OSX binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-osx.tar.gz" \
--file binaries/micro-$1-osx.tar.gz
NL=$'\n'
echo "Uploading Linux 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-linux64.tar.gz" \
--file binaries/micro-$1-linux64.tar.gz
echo "Uploading Linux 64 static binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-linux64-static.tar.gz" \
--file binaries/micro-$1-linux64-static.tar.gz
echo "Uploading Linux 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-linux32.tar.gz" \
--file binaries/micro-$1-linux32.tar.gz
echo "Uploading Linux Arm 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-linux-arm.tar.gz" \
--file binaries/micro-$1-linux-arm.tar.gz
echo "Uploading Linux Arm 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-linux-arm64.tar.gz" \
--file binaries/micro-$1-linux-arm64.tar.gz
echo "Uploading FreeBSD 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-freebsd64.tar.gz" \
--file binaries/micro-$1-freebsd64.tar.gz
echo "Uploading FreeBSD 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-freebsd32.tar.gz" \
--file binaries/micro-$1-freebsd32.tar.gz
echo "Uploading OpenBSD 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-openbsd64.tar.gz" \
--file binaries/micro-$1-openbsd64.tar.gz
echo "Uploading OpenBSD 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-openbsd32.tar.gz" \
--file binaries/micro-$1-openbsd32.tar.gz
echo "Uploading NetBSD 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-netbsd64.tar.gz" \
--file binaries/micro-$1-netbsd64.tar.gz
echo "Uploading NetBSD 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-netbsd32.tar.gz" \
--file binaries/micro-$1-netbsd32.tar.gz
echo "Uploading Windows 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-win64.zip" \
--file binaries/micro-$1-win64.zip
echo "Uploading Windows 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-win32.zip" \
--file binaries/micro-$1-win32.zip
# echo "Uploading vendored tarball"
# github-release upload \
# --user zyedidia \
# --repo micro \
# --tag $tag \
# --name "micro-$1-src.tar.gz" \
# --file binaries/micro-$1-src.tar.gz
#
# echo "Uploading vendored zip"
# github-release upload \
# --user zyedidia \
# --repo micro \
# --tag $tag \
# --name "micro-$1-src.zip" \
# --file binaries/micro-$1-src.zip
echo "Creating new release"
hub release create $tag \
--prerelease \
--message "$1${NL}${NL}$2" \
--attach "binaries/micro-$1-osx.tar.gz" \
--attach "binaries/micro-$1-linux64.tar.gz" \
--attach "binaries/micro-$1-linux64-static.tar.gz" \
--attach "binaries/micro-$1-linux32.tar.gz" \
--attach "binaries/micro-$1-linux-arm.tar.gz" \
--attach "binaries/micro-$1-linux-arm64.tar.gz" \
--attach "binaries/micro-$1-freebsd64.tar.gz" \
--attach "binaries/micro-$1-freebsd32.tar.gz" \
--attach "binaries/micro-$1-openbsd64.tar.gz" \
--attach "binaries/micro-$1-openbsd32.tar.gz" \
--attach "binaries/micro-$1-netbsd64.tar.gz" \
--attach "binaries/micro-$1-netbsd32.tar.gz" \
--attach "binaries/micro-$1-win64.zip" \
--attach "binaries/micro-$1-win32.zip"

View File

@@ -8,144 +8,28 @@ tag="v$1"
echo "Creating tag"
git tag $tag $commitID
git push --tags
hub push --tags
echo "Creating new release"
github-release release \
--user zyedidia \
--repo micro \
--tag $tag \
--name "$1" \
--description "$2" \
NL=$'\n'
echo "Cross compiling binaries"
./cross-compile.sh $1
mv ../binaries .
echo "Uploading OSX binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-osx.tar.gz" \
--file binaries/micro-$1-osx.tar.gz
echo "Uploading Linux 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-linux64.tar.gz" \
--file binaries/micro-$1-linux64.tar.gz
echo "Uploading Linux 64 static binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-linux64-static.tar.gz" \
--file binaries/micro-$1-linux64-static.tar.gz
echo "Uploading Linux 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-linux32.tar.gz" \
--file binaries/micro-$1-linux32.tar.gz
echo "Uploading Linux Arm 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-linux-arm.tar.gz" \
--file binaries/micro-$1-linux-arm.tar.gz
echo "Uploading Linux Arm 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-linux-arm64.tar.gz" \
--file binaries/micro-$1-linux-arm64.tar.gz
echo "Uploading FreeBSD 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-freebsd64.tar.gz" \
--file binaries/micro-$1-freebsd64.tar.gz
echo "Uploading FreeBSD 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-freebsd32.tar.gz" \
--file binaries/micro-$1-freebsd32.tar.gz
echo "Uploading OpenBSD 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-openbsd64.tar.gz" \
--file binaries/micro-$1-openbsd64.tar.gz
echo "Uploading OpenBSD 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-openbsd32.tar.gz" \
--file binaries/micro-$1-openbsd32.tar.gz
echo "Uploading NetBSD 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-netbsd64.tar.gz" \
--file binaries/micro-$1-netbsd64.tar.gz
echo "Uploading NetBSD 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-netbsd32.tar.gz" \
--file binaries/micro-$1-netbsd32.tar.gz
echo "Uploading Windows 64 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-win64.zip" \
--file binaries/micro-$1-win64.zip
echo "Uploading Windows 32 binary"
github-release upload \
--user zyedidia \
--repo micro \
--tag $tag \
--name "micro-$1-win32.zip" \
--file binaries/micro-$1-win32.zip
# echo "Uploading vendored tarball"
# github-release upload \
# --user zyedidia \
# --repo micro \
# --tag $tag \
# --name "micro-$1-src.tar.gz" \
# --file binaries/micro-$1-src.tar.gz
#
# echo "Uploading vendored zip"
# github-release upload \
# --user zyedidia \
# --repo micro \
# --tag $tag \
# --name "micro-$1-src.zip" \
# --file binaries/micro-$1-src.zip
echo "Creating new release"
hub release create $tag \
--message "$1${NL}${NL}$2" \
--attach "binaries/micro-$1-osx.tar.gz" \
--attach "binaries/micro-$1-linux64.tar.gz" \
--attach "binaries/micro-$1-linux64-static.tar.gz" \
--attach "binaries/micro-$1-linux32.tar.gz" \
--attach "binaries/micro-$1-linux-arm.tar.gz" \
--attach "binaries/micro-$1-linux-arm64.tar.gz" \
--attach "binaries/micro-$1-freebsd64.tar.gz" \
--attach "binaries/micro-$1-freebsd32.tar.gz" \
--attach "binaries/micro-$1-openbsd64.tar.gz" \
--attach "binaries/micro-$1-openbsd32.tar.gz" \
--attach "binaries/micro-$1-netbsd64.tar.gz" \
--attach "binaries/micro-$1-netbsd32.tar.gz" \
--attach "binaries/micro-$1-win64.zip" \
--attach "binaries/micro-$1-win32.zip"

View File

@@ -1,255 +0,0 @@
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"regexp"
"strings"
"github.com/robertkrimen/otto/ast"
"github.com/robertkrimen/otto/parser"
)
type walker struct {
nodes []ast.Node
}
func (w *walker) Enter(node ast.Node) ast.Visitor {
w.nodes = append(w.nodes, node)
return w
}
func (w *walker) Exit(node ast.Node) {
}
func getAllNodes(node ast.Node) []ast.Node {
w := &walker{}
ast.Walk(w, node)
return w.nodes
}
func getCalls(node ast.Node, name string) []*ast.CallExpression {
nodes := []*ast.CallExpression{}
for _, n := range getAllNodes(node) {
if ce, ok := n.(*ast.CallExpression); ok {
var calleeName string
switch callee := ce.Callee.(type) {
case *ast.Identifier:
calleeName = callee.Name
case *ast.DotExpression:
calleeName = callee.Identifier.Name
default:
continue
}
if calleeName == name {
nodes = append(nodes, ce)
}
}
}
return nodes
}
func getPropertyValue(node ast.Node, key string) ast.Expression {
for _, p := range node.(*ast.ObjectLiteral).Value {
if p.Key == key {
return p.Value
}
}
return nil
}
type operation struct {
startLine int
startColumn int
endLine int
endColumn int
text []string
}
type check struct {
before []string
operations []operation
after []string
}
type test struct {
description string
checks []check
}
func stringSliceToGoSource(slice []string) string {
var b strings.Builder
b.WriteString("[]string{\n")
for _, s := range slice {
b.WriteString(fmt.Sprintf("%#v,\n", s))
}
b.WriteString("}")
return b.String()
}
func testToGoTest(test test, name string) string {
var b strings.Builder
b.WriteString("func Test")
b.WriteString(name)
b.WriteString("(t *testing.T) {\n")
for _, c := range test.checks {
b.WriteString("check(\n")
b.WriteString("t,\n")
b.WriteString(fmt.Sprintf("%v,\n", stringSliceToGoSource(c.before)))
b.WriteString("[]operation{\n")
for _, op := range c.operations {
b.WriteString("operation{\n")
b.WriteString(fmt.Sprintf("start: Loc{%v, %v},\n", op.startColumn, op.startLine))
b.WriteString(fmt.Sprintf("end: Loc{%v, %v},\n", op.endColumn, op.endLine))
b.WriteString(fmt.Sprintf("text: %v,\n", stringSliceToGoSource(op.text)))
b.WriteString("},\n")
}
b.WriteString("},\n")
b.WriteString(fmt.Sprintf("%v,\n", stringSliceToGoSource(c.after)))
b.WriteString(")\n")
}
b.WriteString("}\n")
return b.String()
}
func nodeToStringSlice(node ast.Node) []string {
var result []string
for _, s := range node.(*ast.ArrayLiteral).Value {
result = append(result, s.(*ast.StringLiteral).Value)
}
return result
}
func nodeToStringSlice2(node ast.Node) []string {
var result []string
for _, o := range node.(*ast.ArrayLiteral).Value {
result = append(result, getPropertyValue(o, "text").(*ast.StringLiteral).Value)
}
return result
}
func nodeToInt(node ast.Node) int {
return int(node.(*ast.NumberLiteral).Value.(int64))
}
func getChecks(node ast.Node) []check {
checks := []check{}
for _, ce := range getCalls(node, "testApplyEdits") {
if len(ce.ArgumentList) != 3 {
// Wrong function
continue
}
before := nodeToStringSlice2(ce.ArgumentList[0])
after := nodeToStringSlice2(ce.ArgumentList[2])
var operations []operation
for _, op := range ce.ArgumentList[1].(*ast.ArrayLiteral).Value {
args := getPropertyValue(op, "range").(*ast.NewExpression).ArgumentList
operations = append(operations, operation{
startLine: nodeToInt(args[0]) - 1,
startColumn: nodeToInt(args[1]) - 1,
endLine: nodeToInt(args[2]) - 1,
endColumn: nodeToInt(args[3]) - 1,
text: []string{getPropertyValue(op, "text").(*ast.StringLiteral).Value},
})
}
checks = append(checks, check{before, operations, after})
}
for _, ce := range getCalls(node, "testApplyEditsWithSyncedModels") {
if len(ce.ArgumentList) > 3 && ce.ArgumentList[3].(*ast.BooleanLiteral).Value {
// inputEditsAreInvalid == true
continue
}
before := nodeToStringSlice(ce.ArgumentList[0])
after := nodeToStringSlice(ce.ArgumentList[2])
var operations []operation
for _, op := range getCalls(ce.ArgumentList[1], "editOp") {
operations = append(operations, operation{
startLine: nodeToInt(op.ArgumentList[0]) - 1,
startColumn: nodeToInt(op.ArgumentList[1]) - 1,
endLine: nodeToInt(op.ArgumentList[2]) - 1,
endColumn: nodeToInt(op.ArgumentList[3]) - 1,
text: nodeToStringSlice(op.ArgumentList[4]),
})
}
checks = append(checks, check{before, operations, after})
}
return checks
}
func getTests(node ast.Node) []test {
tests := []test{}
for _, ce := range getCalls(node, "test") {
description := ce.ArgumentList[0].(*ast.StringLiteral).Value
body := ce.ArgumentList[1].(*ast.FunctionLiteral).Body
checks := getChecks(body)
if len(checks) > 0 {
tests = append(tests, test{description, checks})
}
}
return tests
}
func main() {
var tests []test
for _, filename := range os.Args[1:] {
source, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatalln(err)
}
program, err := parser.ParseFile(nil, "", source, parser.IgnoreRegExpErrors)
if err != nil {
log.Fatalln(err)
}
tests = append(tests, getTests(program)...)
}
if len(tests) == 0 {
log.Fatalln("no tests found!")
}
fmt.Println("// This file is generated from VSCode model tests by the testgen tool.")
fmt.Println("// DO NOT EDIT THIS FILE BY HAND; your changes will be overwritten!\n")
fmt.Println("package buffer")
fmt.Println(`import "testing"`)
re := regexp.MustCompile(`[^\w]`)
usedNames := map[string]bool{}
for _, test := range tests {
name := strings.Title(strings.ToLower(test.description))
name = re.ReplaceAllLiteralString(name, "")
if name == "" {
name = "Unnamed"
}
if usedNames[name] {
for i := 2; ; i++ {
newName := fmt.Sprintf("%v_%v", name, i)
if !usedNames[newName] {
name = newName
break
}
}
}
usedNames[name] = true
fmt.Println(testToGoTest(test, name))
}
}