mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-29 22:27:13 +09:00
Compare commits
119 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
319a5cba74 | ||
|
|
5bfc892a74 | ||
|
|
1793b6268b | ||
|
|
9b62aa4170 | ||
|
|
6fef5d6232 | ||
|
|
fe19b13b3b | ||
|
|
6559b116c0 | ||
|
|
ca976a8a3c | ||
|
|
cfc595e80e | ||
|
|
fde4b92b9f | ||
|
|
b8ec7b320a | ||
|
|
1786165d8b | ||
|
|
0322e91933 | ||
|
|
b2261fc225 | ||
|
|
5ce26cca71 | ||
|
|
efb38b8636 | ||
|
|
0654db334a | ||
|
|
660d345880 | ||
|
|
1f58eecf3c | ||
|
|
ae05ff1811 | ||
|
|
43924646f6 | ||
|
|
79ee757757 | ||
|
|
006165230d | ||
|
|
ead07e0b60 | ||
|
|
140662f1ec | ||
|
|
44c1929f9d | ||
|
|
397fe634d7 | ||
|
|
2e3d08580e | ||
|
|
466889f540 | ||
|
|
63900cb395 | ||
|
|
07860b8973 | ||
|
|
b473fe458d | ||
|
|
8cf56bfc56 | ||
|
|
51050811eb | ||
|
|
14cd3cdbf8 | ||
|
|
51ab8f9914 | ||
|
|
afeb07a024 | ||
|
|
3fc9a8ad9e | ||
|
|
b05d3a5193 | ||
|
|
ffc922a7c5 | ||
|
|
eeab114ed5 | ||
|
|
8bd7e5807c | ||
|
|
9b59e07b47 | ||
|
|
00edf0207f | ||
|
|
a95b17a4e7 | ||
|
|
8956448fca | ||
|
|
a915cf9283 | ||
|
|
dd10869eca | ||
|
|
4356c7e434 | ||
|
|
2e770ce9ce | ||
|
|
381e1b639d | ||
|
|
cc09712d14 | ||
|
|
c5b0c2d41f | ||
|
|
bd43a44194 | ||
|
|
bfe68b1626 | ||
|
|
0064b8268f | ||
|
|
9a22d93ea2 | ||
|
|
5c8a2332d9 | ||
|
|
ff0683d6d0 | ||
|
|
79c0ea17ad | ||
|
|
bdff221870 | ||
|
|
65be5efd83 | ||
|
|
a491dd1c52 | ||
|
|
d7ab44253f | ||
|
|
0a6720498f | ||
|
|
a150eef6f9 | ||
|
|
c46257222c | ||
|
|
299af4a3db | ||
|
|
d0f7ecf9ca | ||
|
|
fb35e0312a | ||
|
|
30395b1f67 | ||
|
|
ddf70953fe | ||
|
|
55e97596d3 | ||
|
|
66dc48ce9b | ||
|
|
c490a94700 | ||
|
|
eff89a98a7 | ||
|
|
221d8f462a | ||
|
|
7a23878250 | ||
|
|
5d3e4fc3d9 | ||
|
|
f52fbfa1f0 | ||
|
|
d60626c64b | ||
|
|
aaac0b1e6f | ||
|
|
0f984131fb | ||
|
|
eb7189dcdb | ||
|
|
74523d28c5 | ||
|
|
f894f0a26e | ||
|
|
a067ce1f41 | ||
|
|
f59468642d | ||
|
|
85e85b7ccc | ||
|
|
8f5888e7bf | ||
|
|
f0da73bae2 | ||
|
|
d92deacf99 | ||
|
|
ffd7b5c770 | ||
|
|
bd8c0d25c8 | ||
|
|
052a36b896 | ||
|
|
a76bf02f5f | ||
|
|
92f4cb7ef7 | ||
|
|
1cf9537340 | ||
|
|
60c8c81da3 | ||
|
|
c76a973877 | ||
|
|
6def99ce24 | ||
|
|
26930ca81f | ||
|
|
cd379cd838 | ||
|
|
ee157f6503 | ||
|
|
48ca19873f | ||
|
|
fee5528309 | ||
|
|
671a188802 | ||
|
|
18d540583b | ||
|
|
943ea15fa3 | ||
|
|
2ef57977d7 | ||
|
|
527750b68d | ||
|
|
629efe5eb7 | ||
|
|
a19cd2e6d0 | ||
|
|
d038d3040f | ||
|
|
9e8d76f2fa | ||
|
|
8a9a14562f | ||
|
|
a6f5dee45c | ||
|
|
b12886b066 | ||
|
|
56f5b475eb |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -11,9 +11,11 @@ todo.txt
|
||||
test.txt
|
||||
log.txt
|
||||
*.old
|
||||
benchmark_results*
|
||||
tools/build-version
|
||||
tools/build-date
|
||||
tools/info-plist
|
||||
tools/bindata
|
||||
tools/vscode-tests/
|
||||
*.hdr
|
||||
assets_vfsdata.go
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "tools/go-bindata"]
|
||||
path = tools/go-bindata
|
||||
url = https://github.com/zyedidia/go-bindata
|
||||
|
||||
27
Makefile
27
Makefile
@@ -8,8 +8,8 @@ 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/internal/util.Version=$(VERSION) -X github.com/zyedidia/micro/internal/util.CommitHash=$(HASH) -X 'github.com/zyedidia/micro/internal/util.CompileDate=$(DATE)'
|
||||
DEBUGVAR = -X github.com/zyedidia/micro/internal/util.Debug=ON
|
||||
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/'
|
||||
|
||||
# Builds micro after checking dependencies but without updating the runtime
|
||||
@@ -45,12 +45,7 @@ fetch-tags:
|
||||
|
||||
# Builds the runtime
|
||||
runtime:
|
||||
git submodule update --init
|
||||
go run runtime/syntax/make_headers.go runtime/syntax
|
||||
go build -o tools/bindata ./tools/go-bindata
|
||||
tools/bindata -pkg config -nomemcopy -nometadata -o runtime.go runtime/...
|
||||
mv runtime.go internal/config
|
||||
gofmt -w internal/config/runtime.go
|
||||
go generate ./internal/config
|
||||
|
||||
testgen:
|
||||
mkdir -p tools/vscode-tests
|
||||
@@ -65,7 +60,21 @@ test:
|
||||
go test ./internal/...
|
||||
|
||||
bench:
|
||||
go test -bench=. ./internal/...
|
||||
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 -alpha 0.15 benchmark_results_baseline benchmark_results
|
||||
|
||||
clean:
|
||||
rm -f micro
|
||||
|
||||
64
README.md
64
README.md
@@ -44,7 +44,7 @@ You can also check out the website for Micro at https://micro-editor.github.io.
|
||||
- Easy to use and install.
|
||||
- No dependencies or external files are needed — just the binary you can download further down the page.
|
||||
- Multiple cursors.
|
||||
- Common keybindings (<kbd>Ctrl+S</kbd>, <kbd>Ctrl+C</kbd>, <kbd>Ctrl+V</kbd>, <kbd>Ctrl+Z</kbd>, …).
|
||||
- Common keybindings (<kbd>Ctrl-s</kbd>, <kbd>Ctrl-c</kbd>, <kbd>Ctrl-v</kbd>, <kbd>Ctrl-z</kbd>, …).
|
||||
- Keybindings can be rebound to your liking.
|
||||
- Sane defaults.
|
||||
- You shouldn't have to configure much out of the box (and it is extremely easy to configure).
|
||||
@@ -53,13 +53,13 @@ You can also check out the website for Micro at https://micro-editor.github.io.
|
||||
- Extremely good mouse support.
|
||||
- This means mouse dragging to create a selection, double click to select by word, and triple click to select by line.
|
||||
- Cross-platform (it should work on all the platforms Go runs on).
|
||||
- Note that while Windows is supported Mingw/Cygwin is not (see below)
|
||||
- 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,17 +76,15 @@ 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>.
|
||||
@@ -97,7 +95,7 @@ You can easily install micro by running
|
||||
curl https://getmic.ro | bash
|
||||
```
|
||||
|
||||
The script will install the micro binary to the current directory. See its [GitHub repository](https://github.com/benweissmann/getmic.ro) for more information.
|
||||
The script will place the micro binary in the current directory. See its [GitHub repository](https://github.com/benweissmann/getmic.ro) for more information.
|
||||
|
||||
### Package managers
|
||||
|
||||
@@ -107,29 +105,35 @@ 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
|
||||
```
|
||||
|
||||
On Debian `unstable | testing | buster-backports` and Ubuntu `focal` (20.04), micro is available
|
||||
via `apt`:
|
||||
**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.
|
||||
|
||||
```
|
||||
sudo apt install micro
|
||||
```
|
||||
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.
|
||||
|
||||
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`
|
||||
* Arch Linux, CRUX, Termux for Android
|
||||
* See details in the [wiki page](https://github.com/zyedidia/micro/wiki/Installing-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`
|
||||
|
||||
### Building from source
|
||||
|
||||
@@ -165,7 +169,7 @@ CGO_ENABLED=0 make build
|
||||
|
||||
### macOS terminal
|
||||
|
||||
If you are using macOS, you should consider using [iTerm2](http://iterm2.com/) instead of the default terminal (Terminal.app). The iTerm2 terminal has much better mouse support as well as better handling of key events. For best keybinding behavior, choose `xterm defaults` under `Preferences->Profiles->Keys->Load Preset`. The newest versions also support true color.
|
||||
If you are using macOS, you should consider using [iTerm2](http://iterm2.com/) instead of the default terminal (Terminal.app). The iTerm2 terminal has much better mouse support as well as better handling of key events. For best keybinding behavior, choose `xterm defaults` under `Preferences->Profiles->Keys->Presets...`, and select `Esc+` for `Left Option Key` in the same menu. The newest versions also support true color.
|
||||
|
||||
If you still insist on using the default Mac terminal, be sure to set `Use Option key as Meta key` under
|
||||
`Preferences->Profiles->Keyboard` to use <kbd>option</kbd> as <kbd>alt</kbd>.
|
||||
@@ -183,7 +187,7 @@ If you don't have these commands, micro will use an internal clipboard for copy
|
||||
|
||||
If you open micro and it doesn't seem like syntax highlighting is working, this is probably because
|
||||
you are using a terminal which does not support 256 color mode. Try changing the color scheme to `simple`
|
||||
by pressing <kbd>Ctrl+E</kbd> in micro and typing `set colorscheme simple`.
|
||||
by pressing <kbd>Ctrl-e</kbd> in micro and typing `set colorscheme simple`.
|
||||
|
||||
If you are using the default Ubuntu terminal, to enable 256 make sure your `TERM` variable is set
|
||||
to `xterm-256color`.
|
||||
@@ -224,7 +228,7 @@ click to enable line selection.
|
||||
|
||||
## Documentation and Help
|
||||
|
||||
micro has a built-in help system which you can access by pressing <kbd>Ctrl+E</kbd> and typing `help`. Additionally, you can
|
||||
micro has a built-in help system which you can access by pressing <kbd>Ctrl-e</kbd> and typing `help`. Additionally, you can
|
||||
view the help files here:
|
||||
|
||||
- [main help](https://github.com/zyedidia/micro/tree/master/runtime/help/help.md)
|
||||
@@ -245,3 +249,5 @@ 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.
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/v2/internal/buffer"
|
||||
"github.com/zyedidia/micro/v2/internal/config"
|
||||
)
|
||||
|
||||
func shouldContinue() bool {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/micro/v2/internal/util"
|
||||
)
|
||||
|
||||
// NullWriter simply sends writes into the void
|
||||
|
||||
@@ -6,14 +6,14 @@ import (
|
||||
lua "github.com/yuin/gopher-lua"
|
||||
luar "layeh.com/gopher-luar"
|
||||
|
||||
"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"
|
||||
"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"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -53,6 +53,9 @@ 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
|
||||
}
|
||||
@@ -83,6 +86,7 @@ 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
|
||||
}
|
||||
@@ -141,6 +145,7 @@ 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)
|
||||
}))
|
||||
|
||||
@@ -5,19 +5,21 @@ 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/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/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/tcell"
|
||||
)
|
||||
|
||||
@@ -43,7 +45,8 @@ 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")
|
||||
fmt.Println("[FILE]:LINE:COL (if the `parsecursor` option is enabled)")
|
||||
fmt.Println("+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")
|
||||
@@ -147,11 +150,45 @@ func LoadInput() []*buffer.Buffer {
|
||||
args := flag.Args()
|
||||
buffers := make([]*buffer.Buffer, 0, len(args))
|
||||
|
||||
if len(args) > 0 {
|
||||
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 {
|
||||
// Option 1
|
||||
// We go through each file and load it
|
||||
for i := 0; i < len(args); i++ {
|
||||
buf, err := buffer.NewBufferFromFile(args[i], buffer.BTDefault)
|
||||
for i := 0; i < len(files); i++ {
|
||||
buf, err := buffer.NewBufferFromFileAtLoc(files[i], btype, flagStartPos)
|
||||
if err != nil {
|
||||
screen.TermMessage(err)
|
||||
continue
|
||||
@@ -168,17 +205,22 @@ func LoadInput() []*buffer.Buffer {
|
||||
screen.TermMessage("Error reading from stdin: ", err)
|
||||
input = []byte{}
|
||||
}
|
||||
buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, buffer.BTDefault))
|
||||
buffers = append(buffers, buffer.NewBufferFromStringAtLoc(string(input), filename, btype, flagStartPos))
|
||||
} else {
|
||||
// Option 3, just open an empty buffer
|
||||
buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, buffer.BTDefault))
|
||||
buffers = append(buffers, buffer.NewBufferFromStringAtLoc(string(input), filename, btype, flagStartPos))
|
||||
}
|
||||
|
||||
return buffers
|
||||
}
|
||||
|
||||
func main() {
|
||||
defer os.Exit(0)
|
||||
defer func() {
|
||||
if util.Stdout.Len() > 0 {
|
||||
fmt.Fprint(os.Stdout, util.Stdout.String())
|
||||
}
|
||||
os.Exit(0)
|
||||
}()
|
||||
|
||||
// runtime.SetCPUProfileRate(400)
|
||||
// f, _ := os.Create("micro.prof")
|
||||
@@ -201,7 +243,10 @@ func main() {
|
||||
if err != nil {
|
||||
screen.TermMessage(err)
|
||||
}
|
||||
config.InitGlobalSettings()
|
||||
err = config.InitGlobalSettings()
|
||||
if err != nil {
|
||||
screen.TermMessage(err)
|
||||
}
|
||||
|
||||
// flag options
|
||||
for k, v := range optionFlags {
|
||||
@@ -335,6 +380,9 @@ func DoEvent() {
|
||||
case <-shell.CloseTerms:
|
||||
case event = <-events:
|
||||
case <-screen.DrawChan():
|
||||
for len(screen.DrawChan()) > 0 {
|
||||
<-screen.DrawChan()
|
||||
}
|
||||
}
|
||||
|
||||
if action.InfoBar.HasPrompt {
|
||||
|
||||
13
go.mod
13
go.mod
@@ -1,4 +1,4 @@
|
||||
module github.com/zyedidia/micro
|
||||
module github.com/zyedidia/micro/v2
|
||||
|
||||
require (
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
@@ -10,19 +10,26 @@ require (
|
||||
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/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749
|
||||
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd // indirect
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb
|
||||
github.com/zyedidia/clipboard v0.0.0-20190823154308-241f98e9b197
|
||||
github.com/zyedidia/clipboard v0.0.0-20200421031010-7c45b8673834
|
||||
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.4
|
||||
github.com/zyedidia/tcell v1.4.6
|
||||
github.com/zyedidia/terminal v0.0.0-20180726154117-533c623e2415
|
||||
golang.org/x/text v0.3.2
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e
|
||||
gopkg.in/sourcemap.v1 v1.0.5 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.7
|
||||
layeh.com/gopher-luar v1.0.7
|
||||
)
|
||||
|
||||
replace github.com/kballard/go-shellquote => github.com/zyedidia/go-shellquote v0.0.0-20200613203517-eccd813c0655
|
||||
|
||||
replace github.com/mattn/go-runewidth => github.com/p-e-w/go-runewidth v0.0.10-0.20200613030200-3e1705c5c059
|
||||
|
||||
go 1.11
|
||||
|
||||
21
go.sum
21
go.sum
@@ -12,8 +12,6 @@ github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdk
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
@@ -23,16 +21,20 @@ github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tW
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/p-e-w/go-runewidth v0.0.10-0.20200613030200-3e1705c5c059 h1:/+h2b6i15wh4EWsFkfdNdBE1jjGA872tpXEyhPM5aYg=
|
||||
github.com/p-e-w/go-runewidth v0.0.10-0.20200613030200-3e1705c5c059/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
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/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk=
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd h1:ug7PpSOB5RBPK1Kg6qskGBoP3Vnj/aNYFTznWvlkGo0=
|
||||
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
|
||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
@@ -40,10 +42,12 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
||||
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=
|
||||
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/go-shellquote v0.0.0-20200613203517-eccd813c0655 h1:Z3RhH6hvcSx7eX6Q/pP6YVsgea/1eMDG99vtWwi3nK4=
|
||||
github.com/zyedidia/go-shellquote v0.0.0-20200613203517-eccd813c0655/go.mod h1:1sTqqO+kcYzZp43M5VsJe1tns9IzlSeC9jB6c2+o/5Y=
|
||||
github.com/zyedidia/highlight v0.0.0-20170330143449-201131ce5cf5 h1:Zs6mpwXvlqpF9zHl5XaN0p5V4J9XvP+WBuiuXyIgqvc=
|
||||
github.com/zyedidia/highlight v0.0.0-20170330143449-201131ce5cf5/go.mod h1:c1r+Ob9tUTPB0FKWO1+x+Hsc/zNa45WdGq7Y38Ybip0=
|
||||
github.com/zyedidia/json5 v0.0.0-20200102012142-2da050b1a98d h1:zmDMkh22zXOB7gz8jFaI4GpI7llsPgzm38/jG0UgxjE=
|
||||
@@ -52,8 +56,8 @@ 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.4 h1:o34LXujNuSueuyTy+5eoQW+rQr8g0UbY8k1NczZyskQ=
|
||||
github.com/zyedidia/tcell v1.4.4/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=
|
||||
@@ -63,6 +67,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
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=
|
||||
|
||||
@@ -5,15 +5,14 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
shellquote "github.com/kballard/go-shellquote"
|
||||
"github.com/zyedidia/clipboard"
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/internal/shell"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/micro/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/tcell"
|
||||
)
|
||||
|
||||
@@ -175,7 +174,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 < utf8.RuneCount(line) && util.IsSpaces(line[h.Cursor.X:h.Cursor.X+tabsize]) && util.IsBytesWhitespace(line[0:h.Cursor.X]) {
|
||||
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]) {
|
||||
for i := 0; i < tabsize; i++ {
|
||||
h.Cursor.Right()
|
||||
}
|
||||
@@ -291,6 +290,19 @@ 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)
|
||||
@@ -325,6 +337,22 @@ 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() {
|
||||
@@ -457,7 +485,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: utf8.RuneCount(line), Y: 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.Cursor.LastVisualX = h.Cursor.GetVisualX()
|
||||
@@ -482,7 +510,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 && utf8.RuneCount(lineStart)%tabSize == 0 {
|
||||
if h.Buf.Settings["tabstospaces"].(bool) && util.IsSpaces(lineStart) && len(lineStart) != 0 && util.CharacterCount(lineStart)%tabSize == 0 {
|
||||
loc := h.Cursor.Loc
|
||||
h.Buf.Remove(loc.Move(-tabSize, h.Buf), loc)
|
||||
} else {
|
||||
@@ -635,7 +663,12 @@ func (h *BufPane) Autocomplete() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if !util.IsNonAlphaNumeric(h.Cursor.RuneUnder(h.Cursor.X)) {
|
||||
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) {
|
||||
// don't autocomplete if cursor is on alpha numeric character (middle of a word)
|
||||
return false
|
||||
}
|
||||
@@ -699,6 +732,7 @@ 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 {
|
||||
@@ -729,6 +763,7 @@ func (h *BufPane) SaveAs() bool {
|
||||
|
||||
// This function saves the buffer to `filename` and changes the buffer's path and name
|
||||
// to `filename` if the save is successful
|
||||
// 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 {
|
||||
@@ -741,6 +776,9 @@ 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) {
|
||||
@@ -751,9 +789,6 @@ func (h *BufPane) saveBufToFile(filename string, action string, callback func())
|
||||
saveWithSudo()
|
||||
h.completeAction(action)
|
||||
}
|
||||
if callback != nil {
|
||||
callback()
|
||||
}
|
||||
})
|
||||
return false
|
||||
}
|
||||
@@ -764,19 +799,32 @@ 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
|
||||
InfoBar.Prompt("Find: ", "", "Find", func(resp string) {
|
||||
prompt := "Find: "
|
||||
if useRegex {
|
||||
prompt = "Find (regex): "
|
||||
}
|
||||
InfoBar.Prompt(prompt, "", "Find", func(resp string) {
|
||||
// Event callback
|
||||
match, found, _ := h.Buf.FindNext(resp, h.Buf.Start(), h.Buf.End(), h.searchOrig, true, true)
|
||||
match, found, _ := h.Buf.FindNext(resp, h.Buf.Start(), h.Buf.End(), h.searchOrig, true, useRegex)
|
||||
if found {
|
||||
h.Cursor.SetSelectionStart(match[0])
|
||||
h.Cursor.SetSelectionEnd(match[1])
|
||||
@@ -791,7 +839,7 @@ func (h *BufPane) Find() 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, true)
|
||||
match, found, err := h.Buf.FindNext(resp, h.Buf.Start(), h.Buf.End(), h.searchOrig, true, useRegex)
|
||||
if err != nil {
|
||||
InfoBar.Error(err)
|
||||
}
|
||||
@@ -802,6 +850,7 @@ func (h *BufPane) Find() 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")
|
||||
@@ -825,7 +874,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, true)
|
||||
match, found, err := h.Buf.FindNext(h.lastSearch, h.Buf.Start(), h.Buf.End(), searchLoc, true, h.lastSearchRegex)
|
||||
if err != nil {
|
||||
InfoBar.Error(err)
|
||||
}
|
||||
@@ -852,7 +901,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, true)
|
||||
match, found, err := h.Buf.FindNext(h.lastSearch, h.Buf.Start(), h.Buf.End(), searchLoc, false, h.lastSearchRegex)
|
||||
if err != nil {
|
||||
InfoBar.Error(err)
|
||||
}
|
||||
@@ -900,6 +949,25 @@ 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()
|
||||
@@ -979,15 +1047,26 @@ 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,
|
||||
)
|
||||
h.Cursor.CurSelection[1].Y -= 1
|
||||
if compensate {
|
||||
h.Cursor.CurSelection[sel].Y -= 1
|
||||
}
|
||||
} else {
|
||||
if h.Cursor.Loc.Y == 0 {
|
||||
InfoBar.Message("Cannot move further up")
|
||||
@@ -1012,8 +1091,14 @@ 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(
|
||||
@@ -1120,6 +1205,16 @@ 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()
|
||||
@@ -1407,8 +1502,9 @@ func (h *BufPane) AddTab() bool {
|
||||
|
||||
// PreviousTab switches to the previous tab in the tab list
|
||||
func (h *BufPane) PreviousTab() bool {
|
||||
a := Tabs.Active()
|
||||
Tabs.SetActive(util.Clamp(a-1, 0, len(Tabs.List)-1))
|
||||
tabsLen := len(Tabs.List)
|
||||
a := Tabs.Active() + tabsLen
|
||||
Tabs.SetActive((a - 1) % tabsLen)
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -1416,7 +1512,8 @@ 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(util.Clamp(a+1, 0, len(Tabs.List)-1))
|
||||
Tabs.SetActive((a + 1) % len(Tabs.List))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ package action
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/v2/internal/screen"
|
||||
)
|
||||
|
||||
// Suspend sends micro to the background. This is the same as pressing CtrlZ in most unix programs.
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"unicode"
|
||||
|
||||
"github.com/zyedidia/json5"
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/v2/internal/config"
|
||||
"github.com/zyedidia/micro/v2/internal/screen"
|
||||
"github.com/zyedidia/tcell"
|
||||
)
|
||||
|
||||
@@ -249,6 +249,7 @@ 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)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
luar "layeh.com/gopher-luar"
|
||||
|
||||
lua "github.com/yuin/gopher-lua"
|
||||
"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/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/tcell"
|
||||
)
|
||||
|
||||
@@ -103,7 +103,7 @@ func BufMapKey(k Event, action string) {
|
||||
afn = f
|
||||
names = append(names, a)
|
||||
} else {
|
||||
screen.TermMessage("Error:", a, "does not exist")
|
||||
screen.TermMessage("Error in bindings: action", a, "does not exist")
|
||||
continue
|
||||
}
|
||||
actionfns = append(actionfns, afn)
|
||||
@@ -124,6 +124,8 @@ func BufMapKey(k Event, action string) {
|
||||
break
|
||||
}
|
||||
}
|
||||
// if the action changed the current pane, update the reference
|
||||
h = MainTab().CurPane()
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -139,6 +141,17 @@ 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
|
||||
@@ -179,7 +192,8 @@ type BufPane struct {
|
||||
tripleClick bool
|
||||
|
||||
// Last search stores the last successful search for FindNext and FindPrev
|
||||
lastSearch string
|
||||
lastSearch string
|
||||
lastSearchRegex bool
|
||||
// Should the current multiple cursor selection search based on word or
|
||||
// based on selection (false for selection, true for word)
|
||||
multiWord bool
|
||||
@@ -318,7 +332,7 @@ func (h *BufPane) HandleEvent(event tcell.Event) {
|
||||
switch e.Buttons() {
|
||||
case tcell.Button1:
|
||||
_, my := e.Position()
|
||||
if h.Buf.Settings["statusline"].(bool) && my >= h.GetView().Y+h.GetView().Height-1 {
|
||||
if h.Buf.Type.Kind != buffer.BTInfo.Kind && h.Buf.Settings["statusline"].(bool) && my >= h.GetView().Y+h.GetView().Height-1 {
|
||||
cancel = true
|
||||
}
|
||||
case tcell.ButtonNone:
|
||||
@@ -343,10 +357,11 @@ 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
|
||||
}
|
||||
}
|
||||
@@ -516,106 +531,111 @@ 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,
|
||||
"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,
|
||||
"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,
|
||||
|
||||
// This was changed to InsertNewline but I don't want to break backwards compatibility
|
||||
"InsertEnter": (*BufPane).InsertNewline,
|
||||
@@ -632,54 +652,57 @@ 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,
|
||||
"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,
|
||||
"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,
|
||||
}
|
||||
|
||||
@@ -10,14 +10,13 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
shellquote "github.com/kballard/go-shellquote"
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/internal/shell"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/micro/v2/internal/buffer"
|
||||
"github.com/zyedidia/micro/v2/internal/config"
|
||||
"github.com/zyedidia/micro/v2/internal/screen"
|
||||
"github.com/zyedidia/micro/v2/internal/shell"
|
||||
"github.com/zyedidia/micro/v2/internal/util"
|
||||
)
|
||||
|
||||
// A Command contains information about how to execute a command
|
||||
@@ -56,6 +55,7 @@ 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,6 +155,56 @@ 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 {
|
||||
@@ -289,7 +339,10 @@ func ReloadConfig() {
|
||||
if err != nil {
|
||||
screen.TermMessage(err)
|
||||
}
|
||||
config.InitGlobalSettings()
|
||||
err = config.InitGlobalSettings()
|
||||
if err != nil {
|
||||
screen.TermMessage(err)
|
||||
}
|
||||
InitBindings()
|
||||
InitCommands()
|
||||
|
||||
@@ -427,6 +480,7 @@ func SetGlobalOptionNative(option string, nativeValue interface{}) error {
|
||||
|
||||
if !local {
|
||||
config.GlobalSettings[option] = nativeValue
|
||||
config.ModifiedSettings[option] = true
|
||||
|
||||
if option == "colorscheme" {
|
||||
// LoadSyntaxFiles()
|
||||
@@ -651,8 +705,11 @@ 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, utf8.RuneCount(h.Buf.LineBytes(line)))
|
||||
col = util.Clamp(col-1, 0, util.CharacterCount(h.Buf.LineBytes(line)))
|
||||
h.Cursor.GotoLoc(buffer.Loc{col, line})
|
||||
} else {
|
||||
line, err := strconv.Atoi(args[0])
|
||||
@@ -660,6 +717,9 @@ 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})
|
||||
}
|
||||
@@ -733,7 +793,8 @@ func (h *BufPane) ReplaceCmd(args []string) {
|
||||
nreplaced := 0
|
||||
start := h.Buf.Start()
|
||||
end := h.Buf.End()
|
||||
if h.Cursor.HasSelection() {
|
||||
selection := h.Cursor.HasSelection()
|
||||
if selection {
|
||||
start = h.Cursor.CurSelection[0]
|
||||
end = h.Cursor.CurSelection[1]
|
||||
}
|
||||
@@ -760,6 +821,9 @@ 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 {
|
||||
@@ -772,7 +836,7 @@ func (h *BufPane) ReplaceCmd(args []string) {
|
||||
nreplaced++
|
||||
} else if !canceled && !yes {
|
||||
searchLoc = locs[0]
|
||||
searchLoc.X += utf8.RuneCount(replace)
|
||||
searchLoc.X += util.CharacterCount(replace)
|
||||
} else if canceled {
|
||||
h.Cursor.ResetSelection()
|
||||
h.Buf.RelocateCursors()
|
||||
@@ -785,14 +849,22 @@ func (h *BufPane) ReplaceCmd(args []string) {
|
||||
}
|
||||
|
||||
h.Buf.RelocateCursors()
|
||||
h.Relocate()
|
||||
|
||||
var s string
|
||||
if nreplaced > 1 {
|
||||
InfoBar.Message("Replaced ", nreplaced, " occurrences of ", search)
|
||||
s = fmt.Sprintf("Replaced %d occurrences of %s", nreplaced, search)
|
||||
} else if nreplaced == 1 {
|
||||
InfoBar.Message("Replaced ", nreplaced, " occurrence of ", search)
|
||||
s = fmt.Sprintf("Replaced 1 occurrence of %s", search)
|
||||
} else {
|
||||
InfoBar.Message("Nothing matched ", search)
|
||||
s = fmt.Sprintf("Nothing matched %s", search)
|
||||
}
|
||||
|
||||
if selection {
|
||||
s += " in selection"
|
||||
}
|
||||
|
||||
InfoBar.Message(s)
|
||||
}
|
||||
|
||||
// ReplaceAllCmd replaces search term all at once
|
||||
@@ -821,7 +893,11 @@ func (h *BufPane) TermCmd(args []string) {
|
||||
|
||||
term := func(i int, newtab bool) {
|
||||
t := new(shell.Terminal)
|
||||
t.Start(args, false, true, nil, nil)
|
||||
err := t.Start(args, false, true, nil, nil)
|
||||
if err != nil {
|
||||
InfoBar.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
id := h.ID()
|
||||
if newtab {
|
||||
|
||||
@@ -17,10 +17,10 @@ func DefaultBindings() map[string]string {
|
||||
"AltDown": "MoveLinesDown",
|
||||
"AltShiftRight": "SelectWordRight",
|
||||
"AltShiftLeft": "SelectWordLeft",
|
||||
"CtrlLeft": "StartOfText",
|
||||
"CtrlLeft": "StartOfTextToggle",
|
||||
"CtrlRight": "EndOfLine",
|
||||
"CtrlShiftLeft": "SelectToStartOfText",
|
||||
"ShiftHome": "SelectToStartOfText",
|
||||
"CtrlShiftLeft": "SelectToStartOfTextToggle",
|
||||
"ShiftHome": "SelectToStartOfTextToggle",
|
||||
"CtrlShiftRight": "SelectToEndOfLine",
|
||||
"ShiftEnd": "SelectToEndOfLine",
|
||||
"CtrlUp": "CursorStart",
|
||||
@@ -43,7 +43,7 @@ func DefaultBindings() map[string]string {
|
||||
"CtrlP": "FindPrevious",
|
||||
"CtrlZ": "Undo",
|
||||
"CtrlY": "Redo",
|
||||
"CtrlC": "Copy",
|
||||
"CtrlC": "CopyLine|Copy",
|
||||
"CtrlX": "Cut",
|
||||
"CtrlK": "CutLine",
|
||||
"CtrlD": "DuplicateLine",
|
||||
@@ -52,7 +52,7 @@ func DefaultBindings() map[string]string {
|
||||
"CtrlT": "AddTab",
|
||||
"Alt,": "PreviousTab",
|
||||
"Alt.": "NextTab",
|
||||
"Home": "StartOfText",
|
||||
"Home": "StartOfTextToggle",
|
||||
"End": "EndOfLine",
|
||||
"CtrlHome": "CursorStart",
|
||||
"CtrlEnd": "CursorEnd",
|
||||
|
||||
@@ -19,10 +19,10 @@ func DefaultBindings() map[string]string {
|
||||
"AltDown": "MoveLinesDown",
|
||||
"CtrlShiftRight": "SelectWordRight",
|
||||
"CtrlShiftLeft": "SelectWordLeft",
|
||||
"AltLeft": "StartOfText",
|
||||
"AltLeft": "StartOfTextToggle",
|
||||
"AltRight": "EndOfLine",
|
||||
"AltShiftLeft": "SelectToStartOfText",
|
||||
"ShiftHome": "SelectToStartOfText",
|
||||
"AltShiftLeft": "SelectToStartOfTextToggle",
|
||||
"ShiftHome": "SelectToStartOfTextToggle",
|
||||
"AltShiftRight": "SelectToEndOfLine",
|
||||
"ShiftEnd": "SelectToEndOfLine",
|
||||
"CtrlUp": "CursorStart",
|
||||
@@ -45,7 +45,7 @@ func DefaultBindings() map[string]string {
|
||||
"CtrlP": "FindPrevious",
|
||||
"CtrlZ": "Undo",
|
||||
"CtrlY": "Redo",
|
||||
"CtrlC": "Copy",
|
||||
"CtrlC": "CopyLine|Copy",
|
||||
"CtrlX": "Cut",
|
||||
"CtrlK": "CutLine",
|
||||
"CtrlD": "DuplicateLine",
|
||||
@@ -54,7 +54,7 @@ func DefaultBindings() map[string]string {
|
||||
"CtrlT": "AddTab",
|
||||
"Alt,": "PreviousTab",
|
||||
"Alt.": "NextTab",
|
||||
"Home": "StartOfText",
|
||||
"Home": "StartOfTextToggle",
|
||||
"End": "EndOfLine",
|
||||
"CtrlHome": "CursorStart",
|
||||
"CtrlEnd": "CursorEnd",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package action
|
||||
|
||||
import "github.com/zyedidia/micro/internal/buffer"
|
||||
import "github.com/zyedidia/micro/v2/internal/buffer"
|
||||
|
||||
var InfoBar *InfoPane
|
||||
var LogBufPane *BufPane
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/micro/v2/internal/buffer"
|
||||
"github.com/zyedidia/micro/v2/internal/config"
|
||||
"github.com/zyedidia/micro/v2/internal/util"
|
||||
)
|
||||
|
||||
// This file is meant (for now) for autocompletion in command mode, not
|
||||
|
||||
@@ -4,10 +4,10 @@ import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/display"
|
||||
"github.com/zyedidia/micro/internal/info"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"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/tcell"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package action
|
||||
|
||||
import (
|
||||
"github.com/zyedidia/micro/internal/display"
|
||||
"github.com/zyedidia/micro/v2/internal/display"
|
||||
)
|
||||
|
||||
type Pane interface {
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/display"
|
||||
"github.com/zyedidia/micro/v2/internal/buffer"
|
||||
"github.com/zyedidia/micro/v2/internal/display"
|
||||
"github.com/zyedidia/tcell"
|
||||
)
|
||||
|
||||
@@ -35,6 +35,13 @@ func (h *RawPane) HandleEvent(event tcell.Event) {
|
||||
}
|
||||
|
||||
h.Buf.Insert(h.Cursor.Loc, reflect.TypeOf(event).String()[7:])
|
||||
|
||||
switch e := event.(type) {
|
||||
case *tcell.EventKey:
|
||||
h.Buf.Insert(h.Cursor.Loc, fmt.Sprintf(": %s", e.Name()))
|
||||
}
|
||||
|
||||
h.Buf.Insert(h.Cursor.Loc, fmt.Sprintf(": %q\n", event.EscSeq()))
|
||||
|
||||
h.Relocate()
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package action
|
||||
|
||||
import (
|
||||
"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/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/tcell"
|
||||
)
|
||||
|
||||
@@ -166,6 +166,8 @@ 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
|
||||
@@ -203,6 +205,8 @@ 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 {
|
||||
@@ -215,22 +219,25 @@ func (t *Tab) HandleEvent(event tcell.Event) {
|
||||
return
|
||||
}
|
||||
|
||||
resizeID := t.GetMouseSplitID(buffer.Loc{mx, my})
|
||||
if resizeID != 0 {
|
||||
t.resizing = t.GetNode(uint64(resizeID))
|
||||
return
|
||||
}
|
||||
if wasReleased {
|
||||
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()
|
||||
|
||||
@@ -4,7 +4,7 @@ package action
|
||||
|
||||
import (
|
||||
shellquote "github.com/kballard/go-shellquote"
|
||||
"github.com/zyedidia/micro/internal/shell"
|
||||
"github.com/zyedidia/micro/v2/internal/shell"
|
||||
)
|
||||
|
||||
// TermEmuSupported is a constant that marks if the terminal emulator is supported
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"runtime"
|
||||
|
||||
"github.com/zyedidia/clipboard"
|
||||
"github.com/zyedidia/micro/internal/display"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/internal/shell"
|
||||
"github.com/zyedidia/micro/v2/internal/display"
|
||||
"github.com/zyedidia/micro/v2/internal/screen"
|
||||
"github.com/zyedidia/micro/v2/internal/shell"
|
||||
"github.com/zyedidia/tcell"
|
||||
"github.com/zyedidia/terminal"
|
||||
)
|
||||
|
||||
@@ -6,9 +6,8 @@ import (
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/micro/v2/internal/util"
|
||||
)
|
||||
|
||||
// A Completer is a function that takes a buffer and returns info
|
||||
@@ -54,7 +53,7 @@ func (b *Buffer) CycleAutocomplete(forward bool) {
|
||||
start := c.Loc
|
||||
end := c.Loc
|
||||
if prevSuggestion < len(b.Suggestions) && prevSuggestion >= 0 {
|
||||
start = end.Move(-utf8.RuneCountInString(b.Completions[prevSuggestion]), b)
|
||||
start = end.Move(-util.CharacterCountInString(b.Completions[prevSuggestion]), b)
|
||||
} else {
|
||||
// end = start.Move(1, b)
|
||||
}
|
||||
@@ -82,7 +81,7 @@ func GetWord(b *Buffer) ([]byte, int) {
|
||||
|
||||
args := bytes.FieldsFunc(l, util.IsNonAlphaNumeric)
|
||||
input := args[len(args)-1]
|
||||
return input, c.X - utf8.RuneCount(input)
|
||||
return input, c.X - util.CharacterCount(input)
|
||||
}
|
||||
|
||||
// GetArg gets the most recent word (separated by ' ' only)
|
||||
@@ -98,7 +97,7 @@ func GetArg(b *Buffer) (string, int) {
|
||||
if i == len(args)-1 {
|
||||
break
|
||||
}
|
||||
argstart += utf8.RuneCount(a) + 1
|
||||
argstart += util.CharacterCount(a) + 1
|
||||
}
|
||||
|
||||
return input, argstart
|
||||
@@ -162,7 +161,7 @@ func BufferComplete(b *Buffer) ([]string, []string) {
|
||||
return []string{}, []string{}
|
||||
}
|
||||
|
||||
inputLen := utf8.RuneCount(input)
|
||||
inputLen := util.CharacterCount(input)
|
||||
|
||||
suggestionsSet := make(map[string]struct{})
|
||||
|
||||
@@ -171,7 +170,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) && utf8.RuneCount(w) > inputLen {
|
||||
if bytes.HasPrefix(w, input) && util.CharacterCount(w) > inputLen {
|
||||
strw := string(w)
|
||||
if _, ok := suggestionsSet[strw]; !ok {
|
||||
suggestionsSet[strw] = struct{}{}
|
||||
@@ -184,7 +183,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) && utf8.RuneCount(w) > inputLen {
|
||||
if bytes.HasPrefix(w, input) && util.CharacterCount(w) > inputLen {
|
||||
strw := string(w)
|
||||
if _, ok := suggestionsSet[strw]; !ok {
|
||||
suggestionsSet[strw] = struct{}{}
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/micro/v2/internal/config"
|
||||
"github.com/zyedidia/micro/v2/internal/screen"
|
||||
"github.com/zyedidia/micro/v2/internal/util"
|
||||
"golang.org/x/text/encoding"
|
||||
)
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -14,16 +15,15 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
luar "layeh.com/gopher-luar"
|
||||
|
||||
dmp "github.com/sergi/go-diff/diffmatchpatch"
|
||||
"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"
|
||||
"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"
|
||||
"golang.org/x/text/encoding/htmlindex"
|
||||
"golang.org/x/text/encoding/unicode"
|
||||
"golang.org/x/text/transform"
|
||||
@@ -60,6 +60,9 @@ 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)
|
||||
@@ -82,6 +85,8 @@ type SharedBuffer struct {
|
||||
// Name of the buffer on the status line
|
||||
name string
|
||||
|
||||
toStdout bool
|
||||
|
||||
// Settings customized by the user
|
||||
Settings map[string]interface{}
|
||||
|
||||
@@ -146,14 +151,14 @@ func (b *SharedBuffer) MarkModified(start, end int) {
|
||||
return
|
||||
}
|
||||
|
||||
start = util.Clamp(start, 0, len(b.lines))
|
||||
end = util.Clamp(end, 0, len(b.lines))
|
||||
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+1)
|
||||
b.Highlighter.HighlightMatches(b, start, l)
|
||||
}
|
||||
|
||||
// DisableReload disables future reloads of this sharedbuffer
|
||||
@@ -186,13 +191,22 @@ type Buffer struct {
|
||||
StartCursor Loc
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// 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) {
|
||||
var err error
|
||||
filename, cursorPos := util.GetPathAndCursorPosition(path)
|
||||
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, err = util.ReplaceHome(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -207,11 +221,6 @@ func NewBufferFromFile(path string, btype BufType) (*Buffer, error) {
|
||||
|
||||
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
|
||||
@@ -223,6 +232,19 @@ func NewBufferFromFile(path string, btype BufType) (*Buffer, error) {
|
||||
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)
|
||||
@@ -275,7 +297,21 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT
|
||||
|
||||
if !hasBackup {
|
||||
reader := bufio.NewReader(transform.NewReader(r, enc.NewDecoder()))
|
||||
b.LineArray = NewLineArray(uint64(size), FFAuto, reader)
|
||||
|
||||
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.EventHandler = NewEventHandler(b.SharedBuffer, b.cursors)
|
||||
|
||||
@@ -355,6 +391,10 @@ 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
|
||||
@@ -464,7 +504,7 @@ func (b *Buffer) RuneAt(loc Loc) rune {
|
||||
if len(line) > 0 {
|
||||
i := 0
|
||||
for len(line) > 0 {
|
||||
r, size := utf8.DecodeRune(line)
|
||||
r, _, size := util.DecodeCharacter(line)
|
||||
line = line[size:]
|
||||
i++
|
||||
|
||||
@@ -538,7 +578,37 @@ 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 {
|
||||
@@ -563,33 +633,8 @@ func (b *Buffer) UpdateRules() {
|
||||
}
|
||||
}
|
||||
|
||||
if syntaxFile == "" {
|
||||
// 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
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if syntaxFile != "" && !foundDef {
|
||||
// we found a syntax file using a syntax header file
|
||||
for _, f := range config.ListRuntimeFiles(config.RTSyntax) {
|
||||
if f.Name() == syntaxFile {
|
||||
data, err := f.Data()
|
||||
@@ -792,19 +837,18 @@ func (b *Buffer) MoveLinesUp(start int, end int) {
|
||||
}
|
||||
l := string(b.LineBytes(start - 1))
|
||||
if end == len(b.lines) {
|
||||
b.Insert(
|
||||
b.insert(
|
||||
Loc{
|
||||
utf8.RuneCount(b.lines[end-1].data),
|
||||
util.CharacterCount(b.lines[end-1].data),
|
||||
end - 1,
|
||||
},
|
||||
"\n"+l,
|
||||
)
|
||||
} else {
|
||||
b.Insert(
|
||||
Loc{0, end},
|
||||
l+"\n",
|
||||
[]byte{'\n'},
|
||||
)
|
||||
}
|
||||
b.Insert(
|
||||
Loc{0, end},
|
||||
l+"\n",
|
||||
)
|
||||
b.Remove(
|
||||
Loc{0, start - 1},
|
||||
Loc{0, start},
|
||||
@@ -813,7 +857,7 @@ func (b *Buffer) MoveLinesUp(start int, end int) {
|
||||
|
||||
// MoveLinesDown moves the range of lines down one row
|
||||
func (b *Buffer) MoveLinesDown(start int, end int) {
|
||||
if start < 0 || start >= end || end >= len(b.lines)-1 {
|
||||
if start < 0 || start >= end || end >= len(b.lines) {
|
||||
return
|
||||
}
|
||||
l := string(b.LineBytes(end))
|
||||
|
||||
@@ -16,7 +16,7 @@ func TestAuto1(t *testing.T) {
|
||||
"",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{1, 0},
|
||||
end: Loc{1, 0},
|
||||
text: []string{
|
||||
@@ -25,7 +25,7 @@ func TestAuto1(t *testing.T) {
|
||||
"fq",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{3, 0},
|
||||
end: Loc{0, 1},
|
||||
text: []string{
|
||||
@@ -58,7 +58,7 @@ func TestAuto2(t *testing.T) {
|
||||
"gmm",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{1, 0},
|
||||
end: Loc{1, 0},
|
||||
text: []string{
|
||||
@@ -66,7 +66,7 @@ func TestAuto2(t *testing.T) {
|
||||
"o",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{3, 1},
|
||||
end: Loc{3, 1},
|
||||
text: []string{
|
||||
@@ -74,7 +74,7 @@ func TestAuto2(t *testing.T) {
|
||||
"avb",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{4, 1},
|
||||
end: Loc{1, 5},
|
||||
text: []string{
|
||||
@@ -111,7 +111,7 @@ func TestAuto3(t *testing.T) {
|
||||
"xuccnb",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{2, 3},
|
||||
end: Loc{2, 3},
|
||||
text: []string{
|
||||
@@ -145,14 +145,14 @@ func TestAuto4(t *testing.T) {
|
||||
"lnqdgorosf",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{2, 0},
|
||||
end: Loc{4, 0},
|
||||
text: []string{
|
||||
"hp",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{6, 0},
|
||||
end: Loc{0, 1},
|
||||
text: []string{
|
||||
@@ -161,7 +161,7 @@ func TestAuto4(t *testing.T) {
|
||||
"mpx",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{1, 1},
|
||||
end: Loc{1, 1},
|
||||
text: []string{
|
||||
@@ -170,7 +170,7 @@ func TestAuto4(t *testing.T) {
|
||||
"",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{1, 1},
|
||||
end: Loc{1, 1},
|
||||
text: []string{
|
||||
@@ -178,7 +178,7 @@ func TestAuto4(t *testing.T) {
|
||||
"mo",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{1, 3},
|
||||
end: Loc{2, 4},
|
||||
text: []string{
|
||||
@@ -210,14 +210,14 @@ func TestBug19872UndoIsFunky(t *testing.T) {
|
||||
"something else",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 1},
|
||||
end: Loc{1, 1},
|
||||
text: []string{
|
||||
"",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 2},
|
||||
end: Loc{1, 3},
|
||||
text: []string{
|
||||
@@ -244,14 +244,14 @@ func TestBug19872UndoIsFunky_2(t *testing.T) {
|
||||
"something else",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 1},
|
||||
end: Loc{0, 1},
|
||||
text: []string{
|
||||
" ",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 2},
|
||||
end: Loc{0, 2},
|
||||
text: []string{
|
||||
@@ -281,7 +281,7 @@ func TestInsertEmptyText(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{0, 0},
|
||||
text: []string{
|
||||
@@ -310,14 +310,14 @@ func TestLastOpIsNoOp(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{1, 0},
|
||||
text: []string{
|
||||
"",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 3},
|
||||
end: Loc{0, 3},
|
||||
text: []string{
|
||||
@@ -346,7 +346,7 @@ func TestInsertTextWithoutNewline1(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{0, 0},
|
||||
text: []string{
|
||||
@@ -375,7 +375,7 @@ func TestInsertTextWithoutNewline2(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{2, 0},
|
||||
end: Loc{2, 0},
|
||||
text: []string{
|
||||
@@ -404,7 +404,7 @@ func TestInsertOneNewline(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{3, 0},
|
||||
end: Loc{3, 0},
|
||||
text: []string{
|
||||
@@ -435,7 +435,7 @@ func TestInsertTextWithOneNewline(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{2, 0},
|
||||
end: Loc{2, 0},
|
||||
text: []string{
|
||||
@@ -466,7 +466,7 @@ func TestInsertTextWithTwoNewlines(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{2, 0},
|
||||
end: Loc{2, 0},
|
||||
text: []string{
|
||||
@@ -499,7 +499,7 @@ func TestInsertTextWithManyNewlines(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{2, 0},
|
||||
end: Loc{2, 0},
|
||||
text: []string{
|
||||
@@ -536,7 +536,7 @@ func TestInsertMultipleNewlines(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{2, 0},
|
||||
end: Loc{2, 0},
|
||||
text: []string{
|
||||
@@ -547,7 +547,7 @@ func TestInsertMultipleNewlines(t *testing.T) {
|
||||
"",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{14, 2},
|
||||
end: Loc{14, 2},
|
||||
text: []string{
|
||||
@@ -582,7 +582,7 @@ func TestDeleteEmptyText(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{0, 0},
|
||||
text: []string{
|
||||
@@ -611,7 +611,7 @@ func TestDeleteTextFromOneLine(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{1, 0},
|
||||
text: []string{
|
||||
@@ -640,7 +640,7 @@ func TestDeleteTextFromOneLine2(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{2, 0},
|
||||
text: []string{
|
||||
@@ -669,7 +669,7 @@ func TestDeleteAllTextFromALine(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{13, 0},
|
||||
text: []string{
|
||||
@@ -698,7 +698,7 @@ func TestDeleteTextFromTwoLines(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{3, 0},
|
||||
end: Loc{5, 1},
|
||||
text: []string{
|
||||
@@ -726,7 +726,7 @@ func TestDeleteTextFromManyLines(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{3, 0},
|
||||
end: Loc{4, 2},
|
||||
text: []string{
|
||||
@@ -753,7 +753,7 @@ func TestDeleteEverything(t *testing.T) {
|
||||
"1",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{1, 4},
|
||||
text: []string{
|
||||
@@ -778,14 +778,14 @@ func TestTwoUnrelatedEdits(t *testing.T) {
|
||||
"123",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 1},
|
||||
end: Loc{2, 1},
|
||||
text: []string{
|
||||
"\t",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 2},
|
||||
end: Loc{4, 2},
|
||||
text: []string{
|
||||
@@ -814,14 +814,14 @@ func TestTwoEditsOnOneLine(t *testing.T) {
|
||||
"\t\t<!@#fifth#@!>\t\t",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{2, 4},
|
||||
end: Loc{6, 4},
|
||||
text: []string{
|
||||
"",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{11, 4},
|
||||
end: Loc{15, 4},
|
||||
text: []string{
|
||||
@@ -846,21 +846,21 @@ func TestManyEdits(t *testing.T) {
|
||||
"{\"x\" : 1}",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{1, 0},
|
||||
end: Loc{1, 0},
|
||||
text: []string{
|
||||
"\n ",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{4, 0},
|
||||
end: Loc{5, 0},
|
||||
text: []string{
|
||||
"",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{8, 0},
|
||||
end: Loc{8, 0},
|
||||
text: []string{
|
||||
@@ -885,21 +885,21 @@ func TestManyEditsReversed(t *testing.T) {
|
||||
"}",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{1, 0},
|
||||
end: Loc{2, 1},
|
||||
text: []string{
|
||||
"",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{5, 1},
|
||||
end: Loc{5, 1},
|
||||
text: []string{
|
||||
" ",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{8, 1},
|
||||
end: Loc{0, 2},
|
||||
text: []string{
|
||||
@@ -924,7 +924,7 @@ func TestReplacingNewlines1(t *testing.T) {
|
||||
"}",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{1, 0},
|
||||
end: Loc{0, 1},
|
||||
text: []string{
|
||||
@@ -932,7 +932,7 @@ func TestReplacingNewlines1(t *testing.T) {
|
||||
"\t",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{10, 1},
|
||||
end: Loc{0, 3},
|
||||
text: []string{
|
||||
@@ -962,7 +962,7 @@ func TestReplacingNewlines2(t *testing.T) {
|
||||
"and the last line",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{4, 0},
|
||||
end: Loc{0, 2},
|
||||
text: []string{
|
||||
@@ -971,7 +971,7 @@ func TestReplacingNewlines2(t *testing.T) {
|
||||
"some more text",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{1, 2},
|
||||
end: Loc{0, 3},
|
||||
text: []string{
|
||||
@@ -981,14 +981,14 @@ func TestReplacingNewlines2(t *testing.T) {
|
||||
"asd",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 4},
|
||||
end: Loc{5, 4},
|
||||
text: []string{
|
||||
"zzzzzzzz",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{10, 4},
|
||||
end: Loc{15, 5},
|
||||
text: []string{
|
||||
@@ -1024,14 +1024,14 @@ func TestAdvanced1(t *testing.T) {
|
||||
" ,\"e\": /*comment*/ [null] }",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{1, 0},
|
||||
text: []string{
|
||||
"",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{2, 0},
|
||||
end: Loc{9, 0},
|
||||
text: []string{
|
||||
@@ -1039,7 +1039,7 @@ func TestAdvanced1(t *testing.T) {
|
||||
" ",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{15, 0},
|
||||
end: Loc{13, 1},
|
||||
text: []string{
|
||||
@@ -1047,7 +1047,7 @@ func TestAdvanced1(t *testing.T) {
|
||||
" ",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{17, 1},
|
||||
end: Loc{8, 2},
|
||||
text: []string{
|
||||
@@ -1055,14 +1055,14 @@ func TestAdvanced1(t *testing.T) {
|
||||
" ",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{21, 2},
|
||||
end: Loc{8, 3},
|
||||
text: []string{
|
||||
"",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{9, 3},
|
||||
end: Loc{9, 3},
|
||||
text: []string{
|
||||
@@ -1070,7 +1070,7 @@ func TestAdvanced1(t *testing.T) {
|
||||
" ",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{27, 3},
|
||||
end: Loc{27, 3},
|
||||
text: []string{
|
||||
@@ -1078,7 +1078,7 @@ func TestAdvanced1(t *testing.T) {
|
||||
" ",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{31, 3},
|
||||
end: Loc{31, 3},
|
||||
text: []string{
|
||||
@@ -1086,7 +1086,7 @@ func TestAdvanced1(t *testing.T) {
|
||||
" ",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{32, 3},
|
||||
end: Loc{33, 3},
|
||||
text: []string{
|
||||
@@ -1116,21 +1116,21 @@ func TestAdvancedSimplified(t *testing.T) {
|
||||
" ,def",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{3, 0},
|
||||
text: []string{
|
||||
"",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{6, 0},
|
||||
end: Loc{1, 1},
|
||||
text: []string{
|
||||
"",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{2, 1},
|
||||
end: Loc{2, 1},
|
||||
text: []string{
|
||||
@@ -1158,7 +1158,7 @@ func TestIssue144(t *testing.T) {
|
||||
"",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{0, 5},
|
||||
text: []string{
|
||||
@@ -1194,7 +1194,7 @@ func TestIssue2586ReplacingSelectedEndOfLineWithNewlineLocksUpTheDocument(t *tes
|
||||
"interesting",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{9, 0},
|
||||
end: Loc{0, 1},
|
||||
text: []string{
|
||||
@@ -1222,7 +1222,7 @@ func TestIssue3980(t *testing.T) {
|
||||
"}",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{7, 0},
|
||||
end: Loc{8, 0},
|
||||
text: []string{
|
||||
@@ -1230,7 +1230,7 @@ func TestIssue3980(t *testing.T) {
|
||||
"",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{16, 2},
|
||||
end: Loc{17, 2},
|
||||
text: []string{
|
||||
@@ -1238,14 +1238,14 @@ func TestIssue3980(t *testing.T) {
|
||||
"",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{17, 2},
|
||||
end: Loc{17, 2},
|
||||
text: []string{
|
||||
" ",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{4, 3},
|
||||
end: Loc{4, 3},
|
||||
text: []string{
|
||||
@@ -1273,14 +1273,14 @@ func TestTouchingEditsTwoInsertsAtTheSamePosition(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{0, 0},
|
||||
text: []string{
|
||||
"a",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{0, 0},
|
||||
text: []string{
|
||||
@@ -1301,14 +1301,14 @@ func TestTouchingEditsInsertAndReplaceTouching(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{0, 0},
|
||||
text: []string{
|
||||
"b",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{2, 0},
|
||||
text: []string{
|
||||
@@ -1329,14 +1329,14 @@ func TestTouchingEditsTwoTouchingReplaces(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{1, 0},
|
||||
text: []string{
|
||||
"H",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{1, 0},
|
||||
end: Loc{2, 0},
|
||||
text: []string{
|
||||
@@ -1357,14 +1357,14 @@ func TestTouchingEditsTwoTouchingDeletes(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{1, 0},
|
||||
text: []string{
|
||||
"",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{1, 0},
|
||||
end: Loc{2, 0},
|
||||
text: []string{
|
||||
@@ -1385,14 +1385,14 @@ func TestTouchingEditsInsertAndReplace(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{0, 0},
|
||||
text: []string{
|
||||
"H",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{2, 0},
|
||||
text: []string{
|
||||
@@ -1413,14 +1413,14 @@ func TestTouchingEditsReplaceAndInsert(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{2, 0},
|
||||
text: []string{
|
||||
"H",
|
||||
},
|
||||
},
|
||||
operation{
|
||||
{
|
||||
start: Loc{2, 0},
|
||||
end: Loc{2, 0},
|
||||
text: []string{
|
||||
@@ -1441,7 +1441,7 @@ func TestSingleDelete1(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{1, 0},
|
||||
text: []string{
|
||||
@@ -1462,7 +1462,7 @@ func TestSingleDelete2(t *testing.T) {
|
||||
"helloworld",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{2, 0},
|
||||
end: Loc{7, 0},
|
||||
text: []string{
|
||||
@@ -1483,7 +1483,7 @@ func TestSingleDelete3(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{5, 0},
|
||||
text: []string{
|
||||
@@ -1504,7 +1504,7 @@ func TestSingleDelete4(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{1, 0},
|
||||
end: Loc{6, 0},
|
||||
text: []string{
|
||||
@@ -1525,7 +1525,7 @@ func TestSingleDelete5(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{11, 0},
|
||||
text: []string{
|
||||
@@ -1548,7 +1548,7 @@ func TestMultiDelete6(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{5, 0},
|
||||
end: Loc{5, 2},
|
||||
text: []string{
|
||||
@@ -1571,7 +1571,7 @@ func TestMultiDelete7(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{11, 0},
|
||||
end: Loc{11, 2},
|
||||
text: []string{
|
||||
@@ -1594,7 +1594,7 @@ func TestMultiDelete8(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{0, 2},
|
||||
text: []string{
|
||||
@@ -1617,7 +1617,7 @@ func TestMultiDelete9(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{11, 0},
|
||||
end: Loc{0, 2},
|
||||
text: []string{
|
||||
@@ -1638,7 +1638,7 @@ func TestSingleInsert1(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{0, 0},
|
||||
text: []string{
|
||||
@@ -1659,7 +1659,7 @@ func TestSingleInsert2(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{1, 0},
|
||||
end: Loc{1, 0},
|
||||
text: []string{
|
||||
@@ -1680,7 +1680,7 @@ func TestSingleInsert3(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{5, 0},
|
||||
end: Loc{5, 0},
|
||||
text: []string{
|
||||
@@ -1701,7 +1701,7 @@ func TestSingleInsert4(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{6, 0},
|
||||
end: Loc{6, 0},
|
||||
text: []string{
|
||||
@@ -1722,7 +1722,7 @@ func TestSingleInsert5(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{11, 0},
|
||||
end: Loc{11, 0},
|
||||
text: []string{
|
||||
@@ -1743,7 +1743,7 @@ func TestMultiInsert6(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{0, 0},
|
||||
end: Loc{0, 0},
|
||||
text: []string{
|
||||
@@ -1765,7 +1765,7 @@ func TestMultiInsert7(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{11, 0},
|
||||
end: Loc{11, 0},
|
||||
text: []string{
|
||||
@@ -1787,7 +1787,7 @@ func TestMultiInsert8(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{6, 0},
|
||||
end: Loc{6, 0},
|
||||
text: []string{
|
||||
@@ -1810,7 +1810,7 @@ func TestMultiInsert9(t *testing.T) {
|
||||
"hello world",
|
||||
},
|
||||
[]operation{
|
||||
operation{
|
||||
{
|
||||
start: Loc{6, 0},
|
||||
end: Loc{6, 0},
|
||||
text: []string{
|
||||
@@ -1825,65 +1825,3 @@ func TestMultiInsert9(t *testing.T) {
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func BenchmarkBuffer(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
TestAuto1(nil)
|
||||
TestAuto2(nil)
|
||||
TestAuto3(nil)
|
||||
TestAuto4(nil)
|
||||
TestBug19872UndoIsFunky(nil)
|
||||
TestBug19872UndoIsFunky_2(nil)
|
||||
TestInsertEmptyText(nil)
|
||||
TestLastOpIsNoOp(nil)
|
||||
TestInsertTextWithoutNewline1(nil)
|
||||
TestInsertTextWithoutNewline2(nil)
|
||||
TestInsertOneNewline(nil)
|
||||
TestInsertTextWithOneNewline(nil)
|
||||
TestInsertTextWithTwoNewlines(nil)
|
||||
TestInsertTextWithManyNewlines(nil)
|
||||
TestInsertMultipleNewlines(nil)
|
||||
TestDeleteEmptyText(nil)
|
||||
TestDeleteTextFromOneLine(nil)
|
||||
TestDeleteTextFromOneLine2(nil)
|
||||
TestDeleteAllTextFromALine(nil)
|
||||
TestDeleteTextFromTwoLines(nil)
|
||||
TestDeleteTextFromManyLines(nil)
|
||||
TestDeleteEverything(nil)
|
||||
TestTwoUnrelatedEdits(nil)
|
||||
TestTwoEditsOnOneLine(nil)
|
||||
TestManyEdits(nil)
|
||||
TestManyEditsReversed(nil)
|
||||
TestReplacingNewlines1(nil)
|
||||
TestReplacingNewlines2(nil)
|
||||
TestAdvanced1(nil)
|
||||
TestAdvancedSimplified(nil)
|
||||
TestIssue144(nil)
|
||||
TestIssue2586ReplacingSelectedEndOfLineWithNewlineLocksUpTheDocument(nil)
|
||||
TestIssue3980(nil)
|
||||
TestTouchingEditsTwoInsertsAtTheSamePosition(nil)
|
||||
TestTouchingEditsInsertAndReplaceTouching(nil)
|
||||
TestTouchingEditsTwoTouchingReplaces(nil)
|
||||
TestTouchingEditsTwoTouchingDeletes(nil)
|
||||
TestTouchingEditsInsertAndReplace(nil)
|
||||
TestTouchingEditsReplaceAndInsert(nil)
|
||||
TestSingleDelete1(nil)
|
||||
TestSingleDelete2(nil)
|
||||
TestSingleDelete3(nil)
|
||||
TestSingleDelete4(nil)
|
||||
TestSingleDelete5(nil)
|
||||
TestMultiDelete6(nil)
|
||||
TestMultiDelete7(nil)
|
||||
TestMultiDelete8(nil)
|
||||
TestMultiDelete9(nil)
|
||||
TestSingleInsert1(nil)
|
||||
TestSingleInsert2(nil)
|
||||
TestSingleInsert3(nil)
|
||||
TestSingleInsert4(nil)
|
||||
TestSingleInsert5(nil)
|
||||
TestMultiInsert6(nil)
|
||||
TestMultiInsert7(nil)
|
||||
TestMultiInsert8(nil)
|
||||
TestMultiInsert9(nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
package buffer
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
testifyAssert "github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/assert"
|
||||
lua "github.com/yuin/gopher-lua"
|
||||
|
||||
ulua "github.com/zyedidia/micro/internal/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 {
|
||||
@@ -16,34 +18,15 @@ type operation struct {
|
||||
text []string
|
||||
}
|
||||
|
||||
type asserter interface {
|
||||
Equal(interface{}, interface{}, ...interface{}) bool
|
||||
NotEqual(interface{}, interface{}, ...interface{}) bool
|
||||
}
|
||||
|
||||
type noOpAsserter struct {
|
||||
}
|
||||
|
||||
func (a *noOpAsserter) Equal(interface{}, interface{}, ...interface{}) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (a *noOpAsserter) NotEqual(interface{}, interface{}, ...interface{}) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
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) {
|
||||
var assert asserter
|
||||
if t == nil {
|
||||
// Benchmark mode; don't perform assertions
|
||||
assert = &noOpAsserter{}
|
||||
} else {
|
||||
assert = testifyAssert.New(t)
|
||||
}
|
||||
assert := assert.New(t)
|
||||
|
||||
b := NewBufferFromString(strings.Join(before, "\n"), "", BTDefault)
|
||||
|
||||
@@ -79,13 +62,14 @@ func check(t *testing.T, before []string, operations []operation, after []string
|
||||
cursor := cursors[i]
|
||||
b.SetCurCursor(cursor.Num)
|
||||
cursor.DeleteSelection()
|
||||
cursor.ResetSelection()
|
||||
b.Insert(cursor.Loc, strings.Join(op.text, "\n"))
|
||||
}
|
||||
|
||||
checkText(after)
|
||||
|
||||
for b.UndoStack.Peek() != nil {
|
||||
// must have exactly two events per operation (delete and insert)
|
||||
for range operations {
|
||||
b.UndoOneEvent()
|
||||
b.UndoOneEvent()
|
||||
}
|
||||
|
||||
@@ -93,7 +77,7 @@ func check(t *testing.T, before []string, operations []operation, after []string
|
||||
|
||||
for i, op := range operations {
|
||||
cursor := cursors[i]
|
||||
if !cursor.HasSelection() {
|
||||
if op.start == op.end {
|
||||
assert.Equal(op.start, cursor.Loc)
|
||||
} else {
|
||||
assert.Equal(op.start, cursor.CurSelection[0])
|
||||
@@ -101,7 +85,8 @@ func check(t *testing.T, before []string, operations []operation, after []string
|
||||
}
|
||||
}
|
||||
|
||||
for b.RedoStack.Peek() != nil {
|
||||
for range operations {
|
||||
b.RedoOneEvent()
|
||||
b.RedoOneEvent()
|
||||
}
|
||||
|
||||
@@ -109,3 +94,229 @@ func check(t *testing.T, before []string, operations []operation, after []string
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package buffer
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/zyedidia/clipboard"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/micro/v2/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 > utf8.RuneCount(buf.LineBytes(pos.Y)) {
|
||||
if pos.Y < 0 || pos.Y >= len(buf.lines) || pos.X < 0 || pos.X > util.CharacterCount(buf.LineBytes(pos.Y)) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -76,9 +74,6 @@ 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)
|
||||
}
|
||||
@@ -102,16 +97,29 @@ func (c *Cursor) Start() {
|
||||
func (c *Cursor) StartOfText() {
|
||||
c.Start()
|
||||
for util.IsWhitespace(c.RuneUnder(c.X)) {
|
||||
if c.X == utf8.RuneCount(c.buf.LineBytes(c.Y)) {
|
||||
if c.X == util.CharacterCount(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 = utf8.RuneCount(c.buf.LineBytes(c.Y))
|
||||
c.X = util.CharacterCount(c.buf.LineBytes(c.Y))
|
||||
c.LastVisualX = c.GetVisualX()
|
||||
}
|
||||
|
||||
@@ -229,8 +237,14 @@ func (c *Cursor) UpN(amount int) {
|
||||
bytes := c.buf.LineBytes(proposedY)
|
||||
c.X = c.GetCharPosInLine(bytes, c.LastVisualX)
|
||||
|
||||
if c.X > utf8.RuneCount(bytes) || (amount < 0 && proposedY == c.Y) {
|
||||
c.X = utf8.RuneCount(bytes)
|
||||
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()
|
||||
}
|
||||
|
||||
c.Y = proposedY
|
||||
@@ -272,7 +286,7 @@ func (c *Cursor) Right() {
|
||||
if c.Loc == c.buf.End() {
|
||||
return
|
||||
}
|
||||
if c.X < utf8.RuneCount(c.buf.LineBytes(c.Y)) {
|
||||
if c.X < util.CharacterCount(c.buf.LineBytes(c.Y)) {
|
||||
c.X++
|
||||
} else {
|
||||
c.Down()
|
||||
@@ -293,8 +307,8 @@ func (c *Cursor) Relocate() {
|
||||
|
||||
if c.X < 0 {
|
||||
c.X = 0
|
||||
} else if c.X > utf8.RuneCount(c.buf.LineBytes(c.Y)) {
|
||||
c.X = utf8.RuneCount(c.buf.LineBytes(c.Y))
|
||||
} else if c.X > util.CharacterCount(c.buf.LineBytes(c.Y)) {
|
||||
c.X = util.CharacterCount(c.buf.LineBytes(c.Y))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +334,7 @@ func (c *Cursor) SelectWord() {
|
||||
c.SetSelectionStart(Loc{backward, c.Y})
|
||||
c.OrigSelection[0] = c.CurSelection[0]
|
||||
|
||||
lineLen := utf8.RuneCount(c.buf.LineBytes(c.Y)) - 1
|
||||
lineLen := util.CharacterCount(c.buf.LineBytes(c.Y)) - 1
|
||||
for forward < lineLen && util.IsWordChar(c.RuneUnder(forward+1)) {
|
||||
forward++
|
||||
}
|
||||
@@ -352,7 +366,7 @@ func (c *Cursor) AddWordToSelection() {
|
||||
if c.Loc.GreaterThan(c.OrigSelection[1]) {
|
||||
forward := c.X
|
||||
|
||||
lineLen := utf8.RuneCount(c.buf.LineBytes(c.Y)) - 1
|
||||
lineLen := util.CharacterCount(c.buf.LineBytes(c.Y)) - 1
|
||||
for forward < lineLen && util.IsWordChar(c.RuneUnder(forward+1)) {
|
||||
forward++
|
||||
}
|
||||
@@ -379,7 +393,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 == utf8.RuneCount(c.buf.LineBytes(c.Y)) {
|
||||
if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) {
|
||||
c.Right()
|
||||
return
|
||||
}
|
||||
@@ -387,7 +401,7 @@ func (c *Cursor) WordRight() {
|
||||
}
|
||||
c.Right()
|
||||
for util.IsWordChar(c.RuneUnder(c.X)) {
|
||||
if c.X == utf8.RuneCount(c.buf.LineBytes(c.Y)) {
|
||||
if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) {
|
||||
return
|
||||
}
|
||||
c.Right()
|
||||
@@ -416,14 +430,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 >= utf8.RuneCount(line) {
|
||||
if len(line) == 0 || x >= util.CharacterCount(line) {
|
||||
return '\n'
|
||||
} else if x < 0 {
|
||||
x = 0
|
||||
}
|
||||
i := 0
|
||||
for len(line) > 0 {
|
||||
r, size := utf8.DecodeRune(line)
|
||||
r, _, size := util.DecodeCharacter(line)
|
||||
line = line[size:]
|
||||
|
||||
if i == x {
|
||||
|
||||
@@ -3,12 +3,12 @@ package buffer
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
dmp "github.com/sergi/go-diff/diffmatchpatch"
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
ulua "github.com/zyedidia/micro/internal/lua"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"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"
|
||||
luar "layeh.com/gopher-luar"
|
||||
)
|
||||
|
||||
@@ -62,10 +62,10 @@ func (eh *EventHandler) DoTextEvent(t *TextEvent, useUndo bool) {
|
||||
var textX int
|
||||
if t.EventType == TextEventInsert {
|
||||
linecount := eh.buf.LinesNum() - oldl
|
||||
textcount := utf8.RuneCount(text)
|
||||
textcount := util.CharacterCount(text)
|
||||
lastnl = bytes.LastIndex(text, []byte{'\n'})
|
||||
if lastnl >= 0 {
|
||||
endX = utf8.RuneCount(text[lastnl+1:])
|
||||
endX = util.CharacterCount(text[lastnl+1:])
|
||||
textX = endX
|
||||
} else {
|
||||
endX = start.X + textcount
|
||||
@@ -123,7 +123,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 + utf8.RuneCount(d.Text), d.Start.Y}
|
||||
t.Deltas[i].End = Loc{d.Start.X + util.CharacterCount(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]
|
||||
@@ -166,12 +166,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(utf8.RuneCountInString(d.Text), eh.buf.LineArray))
|
||||
eh.Remove(loc, loc.MoveLA(util.CharacterCountInString(d.Text), eh.buf.LineArray))
|
||||
} else {
|
||||
if d.Type == dmp.DiffInsert {
|
||||
eh.Insert(loc, d.Text)
|
||||
}
|
||||
loc = loc.MoveLA(utf8.RuneCountInString(d.Text), eh.buf.LineArray)
|
||||
loc = loc.MoveLA(util.CharacterCountInString(d.Text), eh.buf.LineArray)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@ package buffer
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"sync"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/zyedidia/micro/pkg/highlight"
|
||||
"github.com/zyedidia/micro/v2/internal/util"
|
||||
"github.com/zyedidia/micro/v2/pkg/highlight"
|
||||
)
|
||||
|
||||
// Finds the byte index of the nth rune in a byte slice
|
||||
@@ -18,7 +19,7 @@ func runeToByteIndex(n int, txt []byte) int {
|
||||
count := 0
|
||||
i := 0
|
||||
for len(txt) > 0 {
|
||||
_, size := utf8.DecodeRune(txt)
|
||||
_, _, size := util.DecodeCharacter(txt)
|
||||
|
||||
txt = txt[size:]
|
||||
count += size
|
||||
@@ -86,6 +87,8 @@ 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')
|
||||
@@ -152,17 +155,19 @@ 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 {
|
||||
str := make([]byte, 0, la.initsize+1000) // initsize should provide a good estimate
|
||||
b := new(bytes.Buffer)
|
||||
// initsize should provide a good estimate
|
||||
b.Grow(int(la.initsize + 4096))
|
||||
for i, l := range la.lines {
|
||||
str = append(str, l.data...)
|
||||
b.Write(l.data)
|
||||
if i != len(la.lines)-1 {
|
||||
if la.Endings == FFDos {
|
||||
str = append(str, '\r')
|
||||
b.WriteByte('\r')
|
||||
}
|
||||
str = append(str, '\n')
|
||||
b.WriteByte('\n')
|
||||
}
|
||||
}
|
||||
return str
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
// newlineBelow adds a newline below the given line number
|
||||
@@ -296,7 +301,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{utf8.RuneCount(la.lines[numlines-1].data), numlines - 1}
|
||||
return Loc{util.CharacterCount(la.lines[numlines-1].data), numlines - 1}
|
||||
}
|
||||
|
||||
// LineBytes returns line n as an array of bytes
|
||||
|
||||
@@ -46,14 +46,15 @@ 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("ಮಣ್ಣಾಗಿ"))
|
||||
la.insert(Loc{25, 2}, []byte("H̼̥̯͇͙̕͘͞e̸̦̞̠̣̰͙̼̥̦̼̖̬͕͕̰̯̫͇̕ĺ̜̠̩̯̯͙̼̭̠͕̮̞͜l̶͓̫̞̮͈͞ͅo̸͔͙̳̠͈̮̼̳͙̥̲͜͠"))
|
||||
|
||||
sub2 := la.Substr(Loc{0, 2}, Loc{60, 2})
|
||||
assert.Equal(t, []byte("He wonede at Ernleȝe at æಮಣ್ಣಾಗಿðelen are chirechen,"), sub2)
|
||||
assert.Equal(t, []byte("He wonede at Ernleȝe at æH̼̥̯͇͙̕͘͞e̸̦̞̠̣̰͙̼̥̦̼̖̬͕͕̰̯̫͇̕ĺ̜̠̩̯̯͙̼̭̠͕̮̞͜l̶͓̫̞̮͈͞ͅo̸͔͙̳̠͈̮̼̳͙̥̲͜͠ðelen are chirechen,"), sub2)
|
||||
}
|
||||
|
||||
func TestRemove(t *testing.T) {
|
||||
la.remove(Loc{20, 3}, Loc{27, 3})
|
||||
la.remove(Loc{25, 2}, Loc{32, 2})
|
||||
la.remove(Loc{25, 2}, Loc{30, 2})
|
||||
|
||||
bytes := la.Bytes()
|
||||
assert.Equal(t, unicode_txt, string(bytes))
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package buffer
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/micro/v2/internal/util"
|
||||
)
|
||||
|
||||
// Loc stores a location
|
||||
@@ -68,9 +66,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 += utf8.RuneCount(buf.LineBytes(i)) + 1
|
||||
loc += util.CharacterCount(buf.LineBytes(i)) + 1
|
||||
}
|
||||
loc += utf8.RuneCount(buf.LineBytes(a.Y)) - a.X + b.X + 1
|
||||
loc += util.CharacterCount(buf.LineBytes(a.Y)) - a.X + b.X + 1
|
||||
return loc
|
||||
}
|
||||
|
||||
@@ -80,7 +78,7 @@ func (l Loc) right(buf *LineArray) Loc {
|
||||
return Loc{l.X + 1, l.Y}
|
||||
}
|
||||
var res Loc
|
||||
if l.X < utf8.RuneCount(buf.LineBytes(l.Y)) {
|
||||
if l.X < util.CharacterCount(buf.LineBytes(l.Y)) {
|
||||
res = Loc{l.X + 1, l.Y}
|
||||
} else {
|
||||
res = Loc{0, l.Y + 1}
|
||||
@@ -97,7 +95,7 @@ func (l Loc) left(buf *LineArray) Loc {
|
||||
if l.X > 0 {
|
||||
res = Loc{l.X - 1, l.Y}
|
||||
} else {
|
||||
res = Loc{utf8.RuneCount(buf.LineBytes(l.Y - 1)), l.Y - 1}
|
||||
res = Loc{util.CharacterCount(buf.LineBytes(l.Y - 1)), l.Y - 1}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package buffer
|
||||
|
||||
import (
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/v2/internal/config"
|
||||
"github.com/zyedidia/tcell"
|
||||
)
|
||||
|
||||
|
||||
@@ -11,11 +11,10 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/micro/v2/internal/config"
|
||||
"github.com/zyedidia/micro/v2/internal/screen"
|
||||
"github.com/zyedidia/micro/v2/internal/util"
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/htmlindex"
|
||||
"golang.org/x/text/transform"
|
||||
@@ -97,12 +96,11 @@ 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 := utf8.RuneCount(bytes.TrimRightFunc(l.data, unicode.IsSpace))
|
||||
leftover := util.CharacterCount(bytes.TrimRightFunc(l.data, unicode.IsSpace))
|
||||
|
||||
linelen := utf8.RuneCount(l.data)
|
||||
linelen := util.CharacterCount(l.data)
|
||||
b.Remove(Loc{leftover, i}, Loc{linelen, i})
|
||||
}
|
||||
|
||||
@@ -196,5 +194,6 @@ func (b *Buffer) saveToFile(filename string, withSudo bool) error {
|
||||
absPath, _ := filepath.Abs(filename)
|
||||
b.AbsPath = absPath
|
||||
b.isModified = false
|
||||
b.UpdateRules()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@ package buffer
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/micro/v2/internal/util"
|
||||
)
|
||||
|
||||
func (b *Buffer) findDown(r *regexp.Regexp, start, end Loc) ([2]Loc, bool) {
|
||||
@@ -20,19 +19,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 := utf8.RuneCount(l)
|
||||
nchars := util.CharacterCount(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 := utf8.RuneCount(l)
|
||||
nchars := util.CharacterCount(l)
|
||||
start.X = util.Clamp(start.X, 0, nchars)
|
||||
l = util.SliceEnd(l, start.X)
|
||||
charpos = start.X
|
||||
} else if i == end.Y {
|
||||
nchars := utf8.RuneCount(l)
|
||||
nchars := util.CharacterCount(l)
|
||||
end.X = util.Clamp(end.X, 0, nchars)
|
||||
l = util.SliceStart(l, end.X)
|
||||
}
|
||||
@@ -61,19 +60,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 := utf8.RuneCount(l)
|
||||
nchars := util.CharacterCount(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 := utf8.RuneCount(l)
|
||||
nchars := util.CharacterCount(l)
|
||||
start.X = util.Clamp(start.X, 0, nchars)
|
||||
l = util.SliceEnd(l, start.X)
|
||||
charpos = start.X
|
||||
} else if i == end.Y {
|
||||
nchars := utf8.RuneCount(l)
|
||||
nchars := util.CharacterCount(l)
|
||||
end.X = util.Clamp(end.X, 0, nchars)
|
||||
l = util.SliceStart(l, end.X)
|
||||
}
|
||||
@@ -163,12 +162,12 @@ func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []b
|
||||
result = search.Expand(result, replace, in, submatches)
|
||||
}
|
||||
found++
|
||||
netrunes += utf8.RuneCount(in) - utf8.RuneCount(result)
|
||||
netrunes += util.CharacterCount(in) - util.CharacterCount(result)
|
||||
return result
|
||||
})
|
||||
|
||||
from := Loc{charpos, i}
|
||||
to := Loc{charpos + utf8.RuneCount(l), i}
|
||||
to := Loc{charpos + util.CharacterCount(l), i}
|
||||
|
||||
deltas = append(deltas, Delta{newText, from, to})
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
|
||||
"golang.org/x/text/encoding"
|
||||
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/micro/v2/internal/config"
|
||||
"github.com/zyedidia/micro/v2/internal/util"
|
||||
)
|
||||
|
||||
// The SerializedBuffer holds the types that get serialized when a buffer is saved
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package buffer
|
||||
|
||||
import (
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/v2/internal/config"
|
||||
"github.com/zyedidia/micro/v2/internal/screen"
|
||||
)
|
||||
|
||||
func (b *Buffer) SetOptionNative(option string, nativeValue interface{}) error {
|
||||
|
||||
@@ -151,6 +151,9 @@ 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)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"log"
|
||||
|
||||
lua "github.com/yuin/gopher-lua"
|
||||
ulua "github.com/zyedidia/micro/internal/lua"
|
||||
ulua "github.com/zyedidia/micro/v2/internal/lua"
|
||||
)
|
||||
|
||||
// ErrNoSuchFunction is returned when Call is executed on a function that does not exist
|
||||
|
||||
@@ -16,8 +16,8 @@ import (
|
||||
"github.com/blang/semver"
|
||||
lua "github.com/yuin/gopher-lua"
|
||||
"github.com/zyedidia/json5"
|
||||
ulua "github.com/zyedidia/micro/internal/lua"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
ulua "github.com/zyedidia/micro/v2/internal/lua"
|
||||
"github.com/zyedidia/micro/v2/internal/util"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:generate go run runtime_generate.go ../../runtime/syntax ../../runtime
|
||||
package config
|
||||
|
||||
import (
|
||||
@@ -9,6 +10,8 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/zyedidia/micro/v2/internal/vfsutil"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -90,7 +93,7 @@ func (af assetFile) Name() string {
|
||||
}
|
||||
|
||||
func (af assetFile) Data() ([]byte, error) {
|
||||
return Asset(string(af))
|
||||
return vfsutil.ReadFile(Assets, string(af))
|
||||
}
|
||||
|
||||
func (nf namedFile) Name() string {
|
||||
@@ -111,7 +114,10 @@ func AddRealRuntimeFile(fileType RTFiletype, file RuntimeFile) {
|
||||
// AddRuntimeFilesFromDirectory registers each file from the given directory for
|
||||
// the filetype which matches the file-pattern
|
||||
func AddRuntimeFilesFromDirectory(fileType RTFiletype, directory, pattern string) {
|
||||
files, _ := ioutil.ReadDir(directory)
|
||||
files, err := ioutil.ReadDir(directory)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, f := range files {
|
||||
if ok, _ := filepath.Match(pattern, f.Name()); !f.IsDir() && ok {
|
||||
fullPath := filepath.Join(directory, f.Name())
|
||||
@@ -123,13 +129,13 @@ func AddRuntimeFilesFromDirectory(fileType RTFiletype, directory, pattern string
|
||||
// AddRuntimeFilesFromAssets registers each file from the given asset-directory for
|
||||
// the filetype which matches the file-pattern
|
||||
func AddRuntimeFilesFromAssets(fileType RTFiletype, directory, pattern string) {
|
||||
files, err := AssetDir(directory)
|
||||
files, err := vfsutil.ReadDir(Assets, directory)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, f := range files {
|
||||
if ok, _ := path.Match(pattern, f); ok {
|
||||
AddRuntimeFile(fileType, assetFile(path.Join(directory, f)))
|
||||
if ok, _ := path.Match(pattern, f.Name()); ok {
|
||||
AddRuntimeFile(fileType, assetFile(path.Join(directory, f.Name())))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,11 +162,60 @@ func ListRealRuntimeFiles(fileType RTFiletype) []RuntimeFile {
|
||||
return realFiles[fileType]
|
||||
}
|
||||
|
||||
func addPlugin(dirname string, plugdir string, isID func(string) bool, vfs bool) {
|
||||
var srcs []os.FileInfo
|
||||
var err error
|
||||
if vfs {
|
||||
srcs, err = vfsutil.ReadDir(Assets, filepath.Join(plugdir, dirname))
|
||||
} else {
|
||||
srcs, err = ioutil.ReadDir(filepath.Join(plugdir, dirname))
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p := new(Plugin)
|
||||
p.Name = dirname
|
||||
p.DirName = dirname
|
||||
p.Default = vfs
|
||||
for _, f := range srcs {
|
||||
if strings.HasSuffix(f.Name(), ".lua") {
|
||||
if vfs {
|
||||
p.Srcs = append(p.Srcs, assetFile(filepath.Join(plugdir, dirname, f.Name())))
|
||||
} else {
|
||||
p.Srcs = append(p.Srcs, realFile(filepath.Join(plugdir, dirname, f.Name())))
|
||||
}
|
||||
} else if strings.HasSuffix(f.Name(), ".json") {
|
||||
var data []byte
|
||||
var err error
|
||||
|
||||
if vfs {
|
||||
data, err = vfsutil.ReadFile(Assets, filepath.Join(plugdir, dirname, f.Name()))
|
||||
} else {
|
||||
data, err = ioutil.ReadFile(filepath.Join(plugdir, dirname, f.Name()))
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
p.Info, err = NewPluginInfo(data)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
p.Name = p.Info.Name
|
||||
}
|
||||
}
|
||||
|
||||
if !isID(p.Name) || len(p.Srcs) <= 0 {
|
||||
log.Println(p.Name, "is not a plugin")
|
||||
return
|
||||
}
|
||||
Plugins = append(Plugins, p)
|
||||
}
|
||||
|
||||
// InitRuntimeFiles initializes all assets file and the config directory
|
||||
func InitRuntimeFiles() {
|
||||
add := func(fileType RTFiletype, dir, pattern string) {
|
||||
AddRuntimeFilesFromDirectory(fileType, filepath.Join(ConfigDir, dir), pattern)
|
||||
AddRuntimeFilesFromAssets(fileType, path.Join("runtime", dir), pattern)
|
||||
AddRuntimeFilesFromAssets(fileType, dir, pattern)
|
||||
}
|
||||
|
||||
add(RTColorscheme, "colorschemes", "*.micro")
|
||||
@@ -179,68 +234,24 @@ func InitRuntimeFiles() {
|
||||
|
||||
// Search ConfigDir for plugin-scripts
|
||||
plugdir := filepath.Join(ConfigDir, "plug")
|
||||
files, _ := ioutil.ReadDir(plugdir)
|
||||
files, err := ioutil.ReadDir(plugdir)
|
||||
|
||||
isID := regexp.MustCompile(`^[_A-Za-z0-9]+$`).MatchString
|
||||
|
||||
for _, d := range files {
|
||||
if d.IsDir() {
|
||||
srcs, _ := ioutil.ReadDir(filepath.Join(plugdir, d.Name()))
|
||||
p := new(Plugin)
|
||||
p.Name = d.Name()
|
||||
p.DirName = d.Name()
|
||||
for _, f := range srcs {
|
||||
if strings.HasSuffix(f.Name(), ".lua") {
|
||||
p.Srcs = append(p.Srcs, realFile(filepath.Join(plugdir, d.Name(), f.Name())))
|
||||
} else if strings.HasSuffix(f.Name(), ".json") {
|
||||
data, err := ioutil.ReadFile(filepath.Join(plugdir, d.Name(), f.Name()))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
p.Info, err = NewPluginInfo(data)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
p.Name = p.Info.Name
|
||||
}
|
||||
if err == nil {
|
||||
for _, d := range files {
|
||||
if d.IsDir() {
|
||||
addPlugin(d.Name(), plugdir, isID, false)
|
||||
}
|
||||
|
||||
if !isID(p.Name) || len(p.Srcs) <= 0 {
|
||||
log.Println(p.Name, "is not a plugin")
|
||||
continue
|
||||
}
|
||||
Plugins = append(Plugins, p)
|
||||
}
|
||||
}
|
||||
|
||||
plugdir = filepath.Join("runtime", "plugins")
|
||||
if files, err := AssetDir(plugdir); err == nil {
|
||||
plugdir = "plugins"
|
||||
files, err = vfsutil.ReadDir(Assets, plugdir)
|
||||
if err == nil {
|
||||
for _, d := range files {
|
||||
if srcs, err := AssetDir(filepath.Join(plugdir, d)); err == nil {
|
||||
p := new(Plugin)
|
||||
p.Name = d
|
||||
p.DirName = d
|
||||
p.Default = true
|
||||
for _, f := range srcs {
|
||||
if strings.HasSuffix(f, ".lua") {
|
||||
p.Srcs = append(p.Srcs, assetFile(filepath.Join(plugdir, d, f)))
|
||||
} else if strings.HasSuffix(f, ".json") {
|
||||
data, err := Asset(filepath.Join(plugdir, d, f))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
p.Info, err = NewPluginInfo(data)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
p.Name = p.Info.Name
|
||||
}
|
||||
}
|
||||
if !isID(p.Name) || len(p.Srcs) <= 0 {
|
||||
log.Println(p.Name, "is not a plugin")
|
||||
continue
|
||||
}
|
||||
Plugins = append(Plugins, p)
|
||||
if d.IsDir() {
|
||||
addPlugin(d.Name(), plugdir, isID, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -277,7 +288,7 @@ func PluginAddRuntimeFile(plugin string, filetype RTFiletype, filePath string) e
|
||||
if _, err := os.Stat(fullpath); err == nil {
|
||||
AddRealRuntimeFile(filetype, realFile(fullpath))
|
||||
} else {
|
||||
fullpath = path.Join("runtime", "plugins", pldir, filePath)
|
||||
fullpath = path.Join("plugins", pldir, filePath)
|
||||
AddRuntimeFile(filetype, assetFile(fullpath))
|
||||
}
|
||||
return nil
|
||||
@@ -294,7 +305,7 @@ func PluginAddRuntimeFilesFromDirectory(plugin string, filetype RTFiletype, dire
|
||||
if _, err := os.Stat(fullpath); err == nil {
|
||||
AddRuntimeFilesFromDirectory(filetype, fullpath, pattern)
|
||||
} else {
|
||||
fullpath = path.Join("runtime", "plugins", pldir, directory)
|
||||
fullpath = path.Join("plugins", pldir, directory)
|
||||
AddRuntimeFilesFromAssets(filetype, fullpath, pattern)
|
||||
}
|
||||
return nil
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,14 +1,22 @@
|
||||
// +build ignore
|
||||
|
||||
// This script generates the embedded runtime filesystem, and also creates
|
||||
// syntax header metadata which makes loading syntax files at runtime faster
|
||||
// Invoke as go run runtime_generate.go syntaxDir runtimeDir
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/shurcooL/vfsgen"
|
||||
)
|
||||
|
||||
type HeaderYaml struct {
|
||||
@@ -25,19 +33,6 @@ type Header struct {
|
||||
HeaderRgx string
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 1 {
|
||||
os.Chdir(os.Args[1])
|
||||
}
|
||||
files, _ := ioutil.ReadDir(".")
|
||||
for _, f := range files {
|
||||
fname := f.Name()
|
||||
if strings.HasSuffix(fname, ".yaml") {
|
||||
convert(fname[:len(fname)-5])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func convert(name string) {
|
||||
filename := name + ".yaml"
|
||||
var hdr HeaderYaml
|
||||
@@ -61,14 +56,57 @@ func encode(name string, c HeaderYaml) {
|
||||
}
|
||||
|
||||
func decode(name string) Header {
|
||||
start := time.Now()
|
||||
data, _ := ioutil.ReadFile(name + ".hdr")
|
||||
strs := bytes.Split(data, []byte{'\n'})
|
||||
var hdr Header
|
||||
hdr.FileType = string(strs[0])
|
||||
hdr.FNameRgx = string(strs[1])
|
||||
hdr.HeaderRgx = string(strs[2])
|
||||
fmt.Printf("took %v\n", time.Since(start))
|
||||
|
||||
return hdr
|
||||
}
|
||||
|
||||
func main() {
|
||||
orig, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatalln("Couldn't get cwd")
|
||||
return
|
||||
}
|
||||
if len(os.Args) < 2 {
|
||||
log.Fatalln("Not enough arguments")
|
||||
}
|
||||
|
||||
syntaxDir := os.Args[1]
|
||||
assetDir := os.Args[2]
|
||||
|
||||
os.Chdir(syntaxDir)
|
||||
files, _ := ioutil.ReadDir(".")
|
||||
|
||||
// first remove all existing header files (clean the directory)
|
||||
for _, f := range files {
|
||||
fname := f.Name()
|
||||
if strings.HasSuffix(fname, ".hdr") {
|
||||
os.Remove(fname)
|
||||
}
|
||||
}
|
||||
|
||||
// now create a header file for each yaml
|
||||
for _, f := range files {
|
||||
fname := f.Name()
|
||||
if strings.HasSuffix(fname, ".yaml") {
|
||||
convert(fname[:len(fname)-5])
|
||||
}
|
||||
}
|
||||
|
||||
// create the assets_vfsdata.go file for embedding in the binary
|
||||
os.Chdir(orig)
|
||||
|
||||
var assets http.FileSystem = http.Dir(assetDir)
|
||||
err = vfsgen.Generate(assets, vfsgen.Options{
|
||||
PackageName: "config",
|
||||
VariableName: "Assets",
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package config
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -12,7 +13,7 @@ import (
|
||||
|
||||
"github.com/zyedidia/glob"
|
||||
"github.com/zyedidia/json5"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/micro/v2/internal/util"
|
||||
"golang.org/x/text/encoding/htmlindex"
|
||||
)
|
||||
|
||||
@@ -27,9 +28,14 @@ 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{})
|
||||
}
|
||||
|
||||
@@ -75,16 +81,33 @@ 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() {
|
||||
func InitGlobalSettings() error {
|
||||
var err error
|
||||
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
|
||||
@@ -97,6 +120,10 @@ 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
|
||||
}
|
||||
}
|
||||
@@ -109,6 +136,10 @@ 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
|
||||
}
|
||||
}
|
||||
@@ -122,8 +153,25 @@ 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 {
|
||||
parsedSettings[k] = v
|
||||
if def, ok := defaults[k]; !ok || !reflect.DeepEqual(v, def) {
|
||||
if _, wr := ModifiedSettings[k]; wr {
|
||||
parsedSettings[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
txt, _ := json.MarshalIndent(parsedSettings, "", " ")
|
||||
@@ -132,10 +180,23 @@ 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 {
|
||||
txt, _ := json.MarshalIndent(GlobalSettings, "", " ")
|
||||
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, "", " ")
|
||||
err = ioutil.WriteFile(filename, append(txt, '\n'), 0644)
|
||||
}
|
||||
return err
|
||||
@@ -203,6 +264,7 @@ var defaultCommonSettings = map[string]interface{}{
|
||||
"readonly": false,
|
||||
"rmtrailingws": false,
|
||||
"ruler": true,
|
||||
"relativeruler": false,
|
||||
"savecursor": false,
|
||||
"saveundo": false,
|
||||
"scrollbar": false,
|
||||
@@ -248,9 +310,12 @@ 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",
|
||||
|
||||
@@ -2,13 +2,12 @@ package display
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"unicode/utf8"
|
||||
|
||||
runewidth "github.com/mattn/go-runewidth"
|
||||
"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/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/tcell"
|
||||
)
|
||||
|
||||
@@ -73,9 +72,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 := utf8.DecodeRune(b)
|
||||
r, _, size := util.DecodeCharacter(b)
|
||||
|
||||
curStyle, found := w.getStyle(curStyle, bloc, r)
|
||||
curStyle, found := w.getStyle(curStyle, bloc)
|
||||
if found {
|
||||
s = &curStyle
|
||||
}
|
||||
@@ -237,7 +236,7 @@ func (w *BufWindow) LocFromVisual(svloc buffer.Loc) buffer.Loc {
|
||||
return bloc
|
||||
}
|
||||
|
||||
r, size := utf8.DecodeRune(line)
|
||||
r, _, size := util.DecodeCharacter(line)
|
||||
draw()
|
||||
width := 0
|
||||
|
||||
@@ -336,7 +335,14 @@ 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) {
|
||||
lineNum := strconv.Itoa(bloc.Y + 1)
|
||||
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))
|
||||
|
||||
// Write the spaces before the line number if necessary
|
||||
for i := 0; i < maxLineNumLength-len(lineNum); i++ {
|
||||
@@ -360,7 +366,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, r rune) (tcell.Style, bool) {
|
||||
func (w *BufWindow) getStyle(style tcell.Style, bloc buffer.Loc) (tcell.Style, bool) {
|
||||
if group, ok := w.Buf.Match(bloc.Y)[bloc.X]; ok {
|
||||
s := config.GetColor(group.String())
|
||||
return s, true
|
||||
@@ -510,8 +516,15 @@ func (w *BufWindow) displayBuffer() {
|
||||
}
|
||||
bloc.X = bslice
|
||||
|
||||
draw := func(r rune, style tcell.Style, showcursor bool) {
|
||||
draw := func(r rune, combc []rune, style tcell.Style, showcursor bool) {
|
||||
if nColsBeforeStart <= 0 {
|
||||
_, origBg, _ := style.Decompose()
|
||||
_, defBg, _ := config.DefStyle.Decompose()
|
||||
|
||||
// syntax highlighting with non-default background takes precedence
|
||||
// over cursor-line and color-column
|
||||
dontOverrideBackground := origBg != defBg
|
||||
|
||||
for _, c := range cursors {
|
||||
if c.HasSelection() &&
|
||||
(bloc.GreaterEqual(c.CurSelection[0]) && bloc.LessThan(c.CurSelection[1]) ||
|
||||
@@ -524,7 +537,7 @@ func (w *BufWindow) displayBuffer() {
|
||||
}
|
||||
}
|
||||
|
||||
if b.Settings["cursorline"].(bool) && w.active &&
|
||||
if b.Settings["cursorline"].(bool) && w.active && !dontOverrideBackground &&
|
||||
!c.HasSelection() && c.Y == bloc.Y {
|
||||
if s, ok := config.Colorscheme["cursor-line"]; ok {
|
||||
fg, _, _ := s.Decompose()
|
||||
@@ -556,7 +569,7 @@ func (w *BufWindow) displayBuffer() {
|
||||
}
|
||||
|
||||
if s, ok := config.Colorscheme["color-column"]; ok {
|
||||
if colorcolumn != 0 && vloc.X-w.gutterOffset == colorcolumn {
|
||||
if colorcolumn != 0 && vloc.X-w.gutterOffset+w.StartCol == colorcolumn && !dontOverrideBackground {
|
||||
fg, _, _ := s.Decompose()
|
||||
style = style.Background(fg)
|
||||
}
|
||||
@@ -568,7 +581,7 @@ func (w *BufWindow) displayBuffer() {
|
||||
}
|
||||
}
|
||||
|
||||
screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, r, nil, style)
|
||||
screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, r, combc, style)
|
||||
|
||||
if showcursor {
|
||||
for _, c := range cursors {
|
||||
@@ -584,10 +597,11 @@ func (w *BufWindow) displayBuffer() {
|
||||
|
||||
totalwidth := w.StartCol - nColsBeforeStart
|
||||
for len(line) > 0 {
|
||||
r, size := utf8.DecodeRune(line)
|
||||
curStyle, _ = w.getStyle(curStyle, bloc, r)
|
||||
r, combc, size := util.DecodeCharacter(line)
|
||||
|
||||
draw(r, curStyle, true)
|
||||
curStyle, _ = w.getStyle(curStyle, bloc)
|
||||
|
||||
draw(r, combc, curStyle, true)
|
||||
|
||||
width := 0
|
||||
|
||||
@@ -604,7 +618,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, curStyle, false)
|
||||
draw(char, nil, curStyle, false)
|
||||
}
|
||||
}
|
||||
bloc.X++
|
||||
@@ -650,7 +664,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 == colorcolumn {
|
||||
if colorcolumn != 0 && i-w.gutterOffset+w.StartCol == colorcolumn {
|
||||
fg, _, _ := s.Decompose()
|
||||
curStyle = style.Background(fg)
|
||||
}
|
||||
@@ -659,7 +673,8 @@ func (w *BufWindow) displayBuffer() {
|
||||
}
|
||||
|
||||
if vloc.X != bufWidth {
|
||||
draw(' ', curStyle, true)
|
||||
// Display newline within a selection
|
||||
draw(' ', nil, config.DefStyle, true)
|
||||
}
|
||||
|
||||
bloc.X = w.StartCol
|
||||
@@ -682,8 +697,27 @@ 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, '-', nil, config.DefStyle.Reverse(true))
|
||||
screen.SetContent(x, w.Y+w.Height-1, divchar, combc, dividerStyle)
|
||||
}
|
||||
} else {
|
||||
w.drawStatus = false
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package display
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
runewidth "github.com/mattn/go-runewidth"
|
||||
"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/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/tcell"
|
||||
)
|
||||
|
||||
@@ -70,7 +68,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 := utf8.RuneCountInString(i.Msg)
|
||||
n := util.CharacterCountInString(i.Msg)
|
||||
return buffer.Loc{c.GetCharPosInLine(l, vloc.X-n), 0}
|
||||
}
|
||||
|
||||
@@ -86,13 +84,13 @@ func (i *InfoWindow) displayBuffer() {
|
||||
activeC := b.GetActiveCursor()
|
||||
|
||||
blocX := 0
|
||||
vlocX := utf8.RuneCountInString(i.Msg)
|
||||
vlocX := util.CharacterCountInString(i.Msg)
|
||||
|
||||
tabsize := 4
|
||||
line, nColsBeforeStart, bslice := util.SliceVisualEnd(line, blocX, tabsize)
|
||||
blocX = bslice
|
||||
|
||||
draw := func(r rune, style tcell.Style) {
|
||||
draw := func(r rune, combc []rune, style tcell.Style) {
|
||||
if nColsBeforeStart <= 0 {
|
||||
bloc := buffer.Loc{X: blocX, Y: 0}
|
||||
if activeC.HasSelection() &&
|
||||
@@ -112,8 +110,9 @@ func (i *InfoWindow) displayBuffer() {
|
||||
c := r
|
||||
if j > 0 {
|
||||
c = ' '
|
||||
combc = nil
|
||||
}
|
||||
screen.SetContent(vlocX, i.Y, c, nil, style)
|
||||
screen.SetContent(vlocX, i.Y, c, combc, style)
|
||||
}
|
||||
vlocX++
|
||||
}
|
||||
@@ -124,9 +123,9 @@ func (i *InfoWindow) displayBuffer() {
|
||||
for len(line) > 0 {
|
||||
curVX := vlocX
|
||||
curBX := blocX
|
||||
r, size := utf8.DecodeRune(line)
|
||||
r, combc, size := util.DecodeCharacter(line)
|
||||
|
||||
draw(r, i.defStyle())
|
||||
draw(r, combc, i.defStyle())
|
||||
|
||||
width := 0
|
||||
|
||||
@@ -146,7 +145,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, i.defStyle())
|
||||
draw(char, nil, i.defStyle())
|
||||
}
|
||||
}
|
||||
if activeC.X == curBX {
|
||||
@@ -191,7 +190,7 @@ func (i *InfoWindow) scrollToSuggestion() {
|
||||
s := i.totalSize()
|
||||
|
||||
for j, n := range i.Suggestions {
|
||||
c := utf8.RuneCountInString(n)
|
||||
c := util.CharacterCountInString(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)
|
||||
@@ -209,13 +208,13 @@ func (i *InfoWindow) scrollToSuggestion() {
|
||||
}
|
||||
|
||||
func (i *InfoWindow) Display() {
|
||||
i.Clear()
|
||||
x := 0
|
||||
if config.GetGlobalOption("keymenu").(bool) {
|
||||
i.displayKeyMenu()
|
||||
}
|
||||
|
||||
if i.HasPrompt || config.GlobalSettings["infobar"].(bool) {
|
||||
i.Clear()
|
||||
x := 0
|
||||
if config.GetGlobalOption("keymenu").(bool) {
|
||||
i.displayKeyMenu()
|
||||
}
|
||||
|
||||
if !i.HasPrompt && !i.HasMessage && !i.HasError {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,17 +6,16 @@ import (
|
||||
"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/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"
|
||||
"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"
|
||||
)
|
||||
|
||||
// StatusLine represents the information line at the bottom
|
||||
@@ -168,34 +167,36 @@ func (s *StatusLine) Display() {
|
||||
statusLineStyle = style
|
||||
}
|
||||
|
||||
leftLen := util.StringWidth(leftText, utf8.RuneCount(leftText), 1)
|
||||
rightLen := util.StringWidth(rightText, utf8.RuneCount(rightText), 1)
|
||||
leftLen := util.StringWidth(leftText, util.CharacterCount(leftText), 1)
|
||||
rightLen := util.StringWidth(rightText, util.CharacterCount(rightText), 1)
|
||||
|
||||
winX := s.win.X
|
||||
for x := 0; x < s.win.Width; x++ {
|
||||
if x < leftLen {
|
||||
r, size := utf8.DecodeRune(leftText)
|
||||
r, combc, size := util.DecodeCharacter(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, nil, statusLineStyle)
|
||||
screen.SetContent(winX+x, y, c, combc, statusLineStyle)
|
||||
}
|
||||
} else if x >= s.win.Width-rightLen && x < rightLen+s.win.Width-rightLen {
|
||||
r, size := utf8.DecodeRune(rightText)
|
||||
r, combc, size := util.DecodeCharacter(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, nil, statusLineStyle)
|
||||
screen.SetContent(winX+x, y, c, combc, statusLineStyle)
|
||||
}
|
||||
} else {
|
||||
screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package display
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
runewidth "github.com/mattn/go-runewidth"
|
||||
"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/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"
|
||||
)
|
||||
|
||||
type TabWindow struct {
|
||||
@@ -34,7 +32,7 @@ func (w *TabWindow) LocFromVisual(vloc buffer.Loc) int {
|
||||
|
||||
for i, n := range w.Names {
|
||||
x++
|
||||
s := utf8.RuneCountInString(n)
|
||||
s := util.CharacterCountInString(n)
|
||||
if vloc.Y == w.Y && vloc.X < x+s {
|
||||
return i
|
||||
}
|
||||
@@ -75,7 +73,7 @@ func (w *TabWindow) SetActive(a int) {
|
||||
s := w.TotalSize()
|
||||
|
||||
for i, n := range w.Names {
|
||||
c := utf8.RuneCountInString(n)
|
||||
c := util.CharacterCountInString(n)
|
||||
if i == a {
|
||||
if x+c >= w.hscroll+w.Width {
|
||||
w.hscroll = util.Clamp(x+c+1-w.Width, 0, s-w.Width)
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package display
|
||||
|
||||
import (
|
||||
"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/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/tcell"
|
||||
"github.com/zyedidia/terminal"
|
||||
)
|
||||
@@ -98,12 +97,12 @@ func (w *TermWindow) Display() {
|
||||
}
|
||||
|
||||
text := []byte(w.Name())
|
||||
textLen := utf8.RuneCount(text)
|
||||
textLen := util.CharacterCount(text)
|
||||
for x := 0; x < w.Width; x++ {
|
||||
if x < textLen {
|
||||
r, size := utf8.DecodeRune(text)
|
||||
r, combc, size := util.DecodeCharacter(text)
|
||||
text = text[size:]
|
||||
screen.SetContent(w.X+x, w.Y+w.Height, r, nil, statusLineStyle)
|
||||
screen.SetContent(w.X+x, w.Y+w.Height, r, combc, statusLineStyle)
|
||||
} else {
|
||||
screen.SetContent(w.X+x, w.Y+w.Height, ' ', nil, statusLineStyle)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package display
|
||||
|
||||
import (
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/internal/views"
|
||||
"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"
|
||||
)
|
||||
|
||||
type UIWindow struct {
|
||||
@@ -24,11 +25,23 @@ 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, '|', nil, dividerStyle.Reverse(true))
|
||||
screen.SetContent(c.X+c.W, c.Y+h, divchar, combc, dividerStyle)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package display
|
||||
|
||||
import (
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/v2/internal/buffer"
|
||||
)
|
||||
|
||||
type View struct {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/v2/internal/config"
|
||||
)
|
||||
|
||||
// LoadHistory attempts to load user history from configDir/buffers/history
|
||||
|
||||
@@ -3,7 +3,7 @@ package info
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/v2/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(), "")
|
||||
}
|
||||
|
||||
@@ -4,9 +4,10 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"unicode"
|
||||
|
||||
"github.com/zyedidia/micro/internal/config"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
"github.com/zyedidia/micro/v2/internal/config"
|
||||
"github.com/zyedidia/micro/v2/internal/util"
|
||||
"github.com/zyedidia/tcell"
|
||||
)
|
||||
|
||||
@@ -97,6 +98,10 @@ 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
|
||||
@@ -127,7 +132,7 @@ func TempStart(screenWasNil bool) {
|
||||
|
||||
// Init creates and initializes the tcell screen
|
||||
func Init() {
|
||||
drawChan = make(chan bool)
|
||||
drawChan = make(chan bool, 8)
|
||||
|
||||
// Should we enable true color?
|
||||
truecolor := os.Getenv("MICRO_TRUECOLOR") == "1"
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"strings"
|
||||
|
||||
shellquote "github.com/kballard/go-shellquote"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/v2/internal/screen"
|
||||
)
|
||||
|
||||
// ExecCommand executes a command using exec
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"os/exec"
|
||||
"strconv"
|
||||
|
||||
"github.com/zyedidia/micro/internal/buffer"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/v2/internal/buffer"
|
||||
"github.com/zyedidia/micro/v2/internal/screen"
|
||||
"github.com/zyedidia/terminal"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
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 := utf8.DecodeRuneInString(str)
|
||||
r, _, size := DecodeCharacterInString(str)
|
||||
|
||||
str = str[size:]
|
||||
|
||||
@@ -26,7 +22,7 @@ func LuaRuneAt(str string, runeidx int) string {
|
||||
func LuaGetLeadingWhitespace(s string) string {
|
||||
ws := []byte{}
|
||||
for len(s) > 0 {
|
||||
r, size := utf8.DecodeRuneInString(s)
|
||||
r, _, size := DecodeCharacterInString(s)
|
||||
if r == ' ' || r == '\t' {
|
||||
ws = append(ws, byte(r))
|
||||
} else {
|
||||
@@ -40,6 +36,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, _ := utf8.DecodeRuneInString(s)
|
||||
r, _, _ := DecodeCharacterInString(s)
|
||||
return IsWordChar(r)
|
||||
}
|
||||
|
||||
96
internal/util/unicode.go
Normal file
96
internal/util/unicode.go
Normal file
@@ -0,0 +1,96 @@
|
||||
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.
|
||||
|
||||
var minMark = rune(unicode.Mark.R16[0].Lo)
|
||||
|
||||
func isMark(r rune) bool {
|
||||
// Fast path
|
||||
if r < minMark {
|
||||
return false
|
||||
}
|
||||
return unicode.In(r, unicode.Mark)
|
||||
}
|
||||
|
||||
// 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 isMark(c) {
|
||||
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 isMark(c) {
|
||||
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 !isMark(r) {
|
||||
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 !isMark(r) {
|
||||
s++
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -12,7 +13,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/blang/semver"
|
||||
runewidth "github.com/mattn/go-runewidth"
|
||||
@@ -34,6 +34,9 @@ var (
|
||||
// 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() {
|
||||
@@ -46,6 +49,7 @@ func init() {
|
||||
if runtime.GOOS == "windows" {
|
||||
FakeCursor = true
|
||||
}
|
||||
Stdout = new(bytes.Buffer)
|
||||
}
|
||||
|
||||
// SliceEnd returns a byte slice where the index is a rune index
|
||||
@@ -59,7 +63,7 @@ func SliceEnd(slc []byte, index int) []byte {
|
||||
return slc[totalSize:]
|
||||
}
|
||||
|
||||
_, size := utf8.DecodeRune(slc[totalSize:])
|
||||
_, _, size := DecodeCharacter(slc[totalSize:])
|
||||
totalSize += size
|
||||
i++
|
||||
}
|
||||
@@ -77,7 +81,7 @@ func SliceEndStr(str string, index int) string {
|
||||
return str[totalSize:]
|
||||
}
|
||||
|
||||
_, size := utf8.DecodeRuneInString(str[totalSize:])
|
||||
_, _, size := DecodeCharacterInString(str[totalSize:])
|
||||
totalSize += size
|
||||
i++
|
||||
}
|
||||
@@ -96,7 +100,7 @@ func SliceStart(slc []byte, index int) []byte {
|
||||
return slc[:totalSize]
|
||||
}
|
||||
|
||||
_, size := utf8.DecodeRune(slc[totalSize:])
|
||||
_, _, size := DecodeCharacter(slc[totalSize:])
|
||||
totalSize += size
|
||||
i++
|
||||
}
|
||||
@@ -114,7 +118,7 @@ func SliceStartStr(str string, index int) string {
|
||||
return str[:totalSize]
|
||||
}
|
||||
|
||||
_, size := utf8.DecodeRuneInString(str[totalSize:])
|
||||
_, _, size := DecodeCharacterInString(str[totalSize:])
|
||||
totalSize += size
|
||||
i++
|
||||
}
|
||||
@@ -130,7 +134,7 @@ func SliceVisualEnd(b []byte, n, tabsize int) ([]byte, int, int) {
|
||||
width := 0
|
||||
i := 0
|
||||
for len(b) > 0 {
|
||||
r, size := utf8.DecodeRune(b)
|
||||
r, _, size := DecodeCharacter(b)
|
||||
|
||||
w := 0
|
||||
switch r {
|
||||
@@ -167,7 +171,7 @@ func StringWidth(b []byte, n, tabsize int) int {
|
||||
i := 0
|
||||
width := 0
|
||||
for len(b) > 0 {
|
||||
r, size := utf8.DecodeRune(b)
|
||||
r, _, size := DecodeCharacter(b)
|
||||
b = b[size:]
|
||||
|
||||
switch r {
|
||||
@@ -260,7 +264,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 utf8.RuneCount(b[:i])
|
||||
return CharacterCount(b[:i])
|
||||
}
|
||||
|
||||
// MakeRelative will attempt to make a relative path between path and base
|
||||
@@ -339,7 +343,7 @@ func EscapePath(path string) string {
|
||||
func GetLeadingWhitespace(b []byte) []byte {
|
||||
ws := []byte{}
|
||||
for len(b) > 0 {
|
||||
r, size := utf8.DecodeRune(b)
|
||||
r, _, size := DecodeCharacter(b)
|
||||
if r == ' ' || r == '\t' {
|
||||
ws = append(ws, byte(r))
|
||||
} else {
|
||||
@@ -365,7 +369,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 := utf8.DecodeRune(b)
|
||||
r, _, size := DecodeCharacter(b)
|
||||
b = b[size:]
|
||||
|
||||
switch r {
|
||||
@@ -411,7 +415,11 @@ func Clamp(val, min, max int) int {
|
||||
}
|
||||
|
||||
func IsNonAlphaNumeric(c rune) bool {
|
||||
return !unicode.IsLetter(c) && !unicode.IsNumber(c)
|
||||
return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '_'
|
||||
}
|
||||
|
||||
func IsAutocomplete(c rune) bool {
|
||||
return c == '.' || !IsNonAlphaNumeric(c)
|
||||
}
|
||||
|
||||
func ParseSpecial(s string) string {
|
||||
|
||||
21
internal/vfsutil/file.go
Normal file
21
internal/vfsutil/file.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package vfsutil
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
// File implements http.FileSystem using the native file system restricted to a
|
||||
// specific file served at root.
|
||||
//
|
||||
// While the FileSystem.Open method takes '/'-separated paths, a File's string
|
||||
// value is a filename on the native file system, not a URL, so it is separated
|
||||
// by filepath.Separator, which isn't necessarily '/'.
|
||||
type File string
|
||||
|
||||
func (f File) Open(name string) (http.File, error) {
|
||||
if name != "/" {
|
||||
return nil, &os.PathError{Op: "open", Path: name, Err: os.ErrNotExist}
|
||||
}
|
||||
return os.Open(string(f))
|
||||
}
|
||||
39
internal/vfsutil/vfsutil.go
Normal file
39
internal/vfsutil/vfsutil.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// Package vfsutil implements some I/O utility functions for http.FileSystem.
|
||||
package vfsutil
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
// ReadDir reads the contents of the directory associated with file and
|
||||
// returns a slice of FileInfo values in directory order.
|
||||
func ReadDir(fs http.FileSystem, name string) ([]os.FileInfo, error) {
|
||||
f, err := fs.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
return f.Readdir(0)
|
||||
}
|
||||
|
||||
// Stat returns the FileInfo structure describing file.
|
||||
func Stat(fs http.FileSystem, name string) (os.FileInfo, error) {
|
||||
f, err := fs.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
return f.Stat()
|
||||
}
|
||||
|
||||
// ReadFile reads the file named by path from fs and returns the contents.
|
||||
func ReadFile(fs http.FileSystem, path string) ([]byte, error) {
|
||||
rc, err := fs.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rc.Close()
|
||||
return ioutil.ReadAll(rc)
|
||||
}
|
||||
146
internal/vfsutil/walk.go
Normal file
146
internal/vfsutil/walk.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package vfsutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Walk walks the filesystem rooted at root, calling walkFn for each file or
|
||||
// directory in the filesystem, including root. All errors that arise visiting files
|
||||
// and directories are filtered by walkFn. The files are walked in lexical
|
||||
// order.
|
||||
func Walk(fs http.FileSystem, root string, walkFn filepath.WalkFunc) error {
|
||||
info, err := Stat(fs, root)
|
||||
if err != nil {
|
||||
return walkFn(root, nil, err)
|
||||
}
|
||||
return walk(fs, root, info, walkFn)
|
||||
}
|
||||
|
||||
// readDirNames reads the directory named by dirname and returns
|
||||
// a sorted list of directory entries.
|
||||
func readDirNames(fs http.FileSystem, dirname string) ([]string, error) {
|
||||
fis, err := ReadDir(fs, dirname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
names := make([]string, len(fis))
|
||||
for i := range fis {
|
||||
names[i] = fis[i].Name()
|
||||
}
|
||||
sort.Strings(names)
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// walk recursively descends path, calling walkFn.
|
||||
func walk(fs http.FileSystem, path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
|
||||
err := walkFn(path, info, nil)
|
||||
if err != nil {
|
||||
if info.IsDir() && err == filepath.SkipDir {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
names, err := readDirNames(fs, path)
|
||||
if err != nil {
|
||||
return walkFn(path, info, err)
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
filename := pathpkg.Join(path, name)
|
||||
fileInfo, err := Stat(fs, filename)
|
||||
if err != nil {
|
||||
if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = walk(fs, filename, fileInfo, walkFn)
|
||||
if err != nil {
|
||||
if !fileInfo.IsDir() || err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WalkFilesFunc is the type of the function called for each file or directory visited by WalkFiles.
|
||||
// It's like filepath.WalkFunc, except it provides an additional ReadSeeker parameter for file being visited.
|
||||
type WalkFilesFunc func(path string, info os.FileInfo, rs io.ReadSeeker, err error) error
|
||||
|
||||
// WalkFiles walks the filesystem rooted at root, calling walkFn for each file or
|
||||
// directory in the filesystem, including root. In addition to FileInfo, it passes an
|
||||
// ReadSeeker to walkFn for each file it visits.
|
||||
func WalkFiles(fs http.FileSystem, root string, walkFn WalkFilesFunc) error {
|
||||
file, info, err := openStat(fs, root)
|
||||
if err != nil {
|
||||
return walkFn(root, nil, nil, err)
|
||||
}
|
||||
return walkFiles(fs, root, info, file, walkFn)
|
||||
}
|
||||
|
||||
// walkFiles recursively descends path, calling walkFn.
|
||||
// It closes the input file after it's done with it, so the caller shouldn't.
|
||||
func walkFiles(fs http.FileSystem, path string, info os.FileInfo, file http.File, walkFn WalkFilesFunc) error {
|
||||
err := walkFn(path, info, file, nil)
|
||||
file.Close()
|
||||
if err != nil {
|
||||
if info.IsDir() && err == filepath.SkipDir {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
names, err := readDirNames(fs, path)
|
||||
if err != nil {
|
||||
return walkFn(path, info, nil, err)
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
filename := pathpkg.Join(path, name)
|
||||
file, fileInfo, err := openStat(fs, filename)
|
||||
if err != nil {
|
||||
if err := walkFn(filename, nil, nil, err); err != nil && err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = walkFiles(fs, filename, fileInfo, file, walkFn)
|
||||
// file is closed by walkFiles, so we don't need to close it here.
|
||||
if err != nil {
|
||||
if !fileInfo.IsDir() || err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// openStat performs Open and Stat and returns results, or first error encountered.
|
||||
// The caller is responsible for closing the returned file when done.
|
||||
func openStat(fs http.FileSystem, name string) (http.File, os.FileInfo, error) {
|
||||
f, err := fs.Open(name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
return f, fi, nil
|
||||
}
|
||||
93
internal/vfsutil/walk_test.go
Normal file
93
internal/vfsutil/walk_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package vfsutil_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/shurcooL/httpfs/vfsutil"
|
||||
"golang.org/x/tools/godoc/vfs/httpfs"
|
||||
"golang.org/x/tools/godoc/vfs/mapfs"
|
||||
)
|
||||
|
||||
func ExampleWalk() {
|
||||
var fs http.FileSystem = httpfs.New(mapfs.New(map[string]string{
|
||||
"zzz-last-file.txt": "It should be visited last.",
|
||||
"a-file.txt": "It has stuff.",
|
||||
"another-file.txt": "Also stuff.",
|
||||
"folderA/entry-A.txt": "Alpha.",
|
||||
"folderA/entry-B.txt": "Beta.",
|
||||
}))
|
||||
|
||||
walkFn := func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
log.Printf("can't stat file %s: %v\n", path, err)
|
||||
return nil
|
||||
}
|
||||
fmt.Println(path)
|
||||
return nil
|
||||
}
|
||||
|
||||
err := vfsutil.Walk(fs, "/", walkFn)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// /
|
||||
// /a-file.txt
|
||||
// /another-file.txt
|
||||
// /folderA
|
||||
// /folderA/entry-A.txt
|
||||
// /folderA/entry-B.txt
|
||||
// /zzz-last-file.txt
|
||||
}
|
||||
|
||||
func ExampleWalkFiles() {
|
||||
var fs http.FileSystem = httpfs.New(mapfs.New(map[string]string{
|
||||
"zzz-last-file.txt": "It should be visited last.",
|
||||
"a-file.txt": "It has stuff.",
|
||||
"another-file.txt": "Also stuff.",
|
||||
"folderA/entry-A.txt": "Alpha.",
|
||||
"folderA/entry-B.txt": "Beta.",
|
||||
}))
|
||||
|
||||
walkFn := func(path string, fi os.FileInfo, r io.ReadSeeker, err error) error {
|
||||
if err != nil {
|
||||
log.Printf("can't stat file %s: %v\n", path, err)
|
||||
return nil
|
||||
}
|
||||
fmt.Println(path)
|
||||
if !fi.IsDir() {
|
||||
b, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
log.Printf("can't read file %s: %v\n", path, err)
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("%q\n", b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
err := vfsutil.WalkFiles(fs, "/", walkFn)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// /
|
||||
// /a-file.txt
|
||||
// "It has stuff."
|
||||
// /another-file.txt
|
||||
// "Also stuff."
|
||||
// /folderA
|
||||
// /folderA/entry-A.txt
|
||||
// "Alpha."
|
||||
// /folderA/entry-B.txt
|
||||
// "Beta."
|
||||
// /zzz-last-file.txt
|
||||
// "It should be visited last."
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package highlight
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func sliceStart(slc []byte, index int) []byte {
|
||||
@@ -15,7 +14,7 @@ func sliceStart(slc []byte, index int) []byte {
|
||||
return slc[totalSize:]
|
||||
}
|
||||
|
||||
_, size := utf8.DecodeRune(slc[totalSize:])
|
||||
_, _, size := DecodeCharacter(slc[totalSize:])
|
||||
totalSize += size
|
||||
i++
|
||||
}
|
||||
@@ -32,7 +31,7 @@ func sliceEnd(slc []byte, index int) []byte {
|
||||
return slc[:totalSize]
|
||||
}
|
||||
|
||||
_, size := utf8.DecodeRune(slc[totalSize:])
|
||||
_, _, size := DecodeCharacter(slc[totalSize:])
|
||||
totalSize += size
|
||||
i++
|
||||
}
|
||||
@@ -47,9 +46,9 @@ func runePos(p int, str []byte) int {
|
||||
return 0
|
||||
}
|
||||
if p >= len(str) {
|
||||
return utf8.RuneCount(str)
|
||||
return CharacterCount(str)
|
||||
}
|
||||
return utf8.RuneCount(str[:p])
|
||||
return CharacterCount(str[:p])
|
||||
}
|
||||
|
||||
func combineLineMatch(src, dst LineMatch) LineMatch {
|
||||
@@ -112,7 +111,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, utf8.RuneCount(match))
|
||||
res := make([]byte, CharacterCount(match))
|
||||
return res
|
||||
})
|
||||
} else {
|
||||
@@ -148,7 +147,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 := utf8.RuneCount(line)
|
||||
lineLen := CharacterCount(line)
|
||||
if start == 0 {
|
||||
if !statesOnly {
|
||||
if _, ok := highlights[0]; !ok {
|
||||
@@ -236,7 +235,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 := utf8.RuneCount(line)
|
||||
lineLen := CharacterCount(line)
|
||||
if lineLen == 0 {
|
||||
if canMatchEnd {
|
||||
h.lastRegion = nil
|
||||
@@ -336,11 +335,11 @@ func (h *Highlighter) HighlightStates(input LineStates) {
|
||||
}
|
||||
}
|
||||
|
||||
// HighlightMatches sets the matches for each line in between startline and endline
|
||||
// HighlightMatches sets the matches for each line from startline to 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
|
||||
}
|
||||
|
||||
85
pkg/highlight/unicode.go
Normal file
85
pkg/highlight/unicode.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package highlight
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
var minMark = rune(unicode.Mark.R16[0].Lo)
|
||||
|
||||
func isMark(r rune) bool {
|
||||
// Fast path
|
||||
if r < minMark {
|
||||
return false
|
||||
}
|
||||
return unicode.In(r, unicode.Mark)
|
||||
}
|
||||
|
||||
// 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 isMark(c) {
|
||||
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 isMark(c) {
|
||||
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 !isMark(r) {
|
||||
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 !isMark(r) {
|
||||
s++
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
34
runtime/colorschemes/dukedark-tc.micro
Normal file
34
runtime/colorschemes/dukedark-tc.micro
Normal file
@@ -0,0 +1,34 @@
|
||||
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"
|
||||
34
runtime/colorschemes/dukelight-tc.micro
Normal file
34
runtime/colorschemes/dukelight-tc.micro
Normal file
@@ -0,0 +1,34 @@
|
||||
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"
|
||||
34
runtime/colorschemes/dukeubuntu-tc.micro
Normal file
34
runtime/colorschemes/dukeubuntu-tc.micro
Normal file
@@ -0,0 +1,34 @@
|
||||
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"
|
||||
@@ -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,#353535"
|
||||
color-link line-number "#a1a1a1,#232323"
|
||||
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 "#a1a1a1,#414141"
|
||||
color-link tabbar "bold #a1a1a1,#414141"
|
||||
color-link statusline "#b1b1b1,#232323"
|
||||
color-link tabbar "bold #b1b1b1,#232323"
|
||||
color-link cursor-line "#353535"
|
||||
color-link color-column "#353535"
|
||||
color-link space "underline #e6e1dc,#2b2b2b"
|
||||
|
||||
@@ -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, or underline in front of the color:
|
||||
You can also put bold, italic, or underline in front of the color:
|
||||
|
||||
```
|
||||
color-link comment "bold red"
|
||||
|
||||
@@ -62,6 +62,11 @@ 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.
|
||||
|
||||
|
||||
@@ -11,115 +11,115 @@ can change it!
|
||||
|
||||
| Key | Description of function |
|
||||
|---------- |-------------------------------------------------------------------------------------------------- |
|
||||
| Ctrl+E | Open a command prompt for running commands (see `> help commands` for a list of valid commands). |
|
||||
| Ctrl-e | Open a command prompt for running commands (see `> help commands` for a list of valid commands). |
|
||||
| Tab | In command prompt, it will autocomplete if possible. |
|
||||
| Ctrl+B | Run a shell command (this will close micro while your command executes). |
|
||||
| Ctrl-b | Run a shell command (this will close micro while your command executes). |
|
||||
|
||||
### Navigation
|
||||
|
||||
| Key | Description of function |
|
||||
|---------------------------- |------------------------------------------------------------------------------------------ |
|
||||
| Arrows | Move the cursor around |
|
||||
| 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 the current line |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| Alt+{ | Move cursor to previous empty line, or beginning of document |
|
||||
| Alt+} | Move cursor to next empty line, or end of document |
|
||||
| Ctrl(Alt on Mac)-LeftArrow | Move cursor one word left |
|
||||
| Ctrl(Alt on Mac)-RightArrow | Move cursor one word right |
|
||||
| Alt-{ | Move cursor to previous empty line, or beginning of document |
|
||||
| Alt-} | Move cursor to next empty line, or end of document |
|
||||
| PageUp | Move cursor up one page |
|
||||
| PageDown | Move cursor down one page |
|
||||
| Ctrl+Home or Ctrl+UpArrow | Move cursor to start of document |
|
||||
| Ctrl+End or Ctrl+DownArrow | Move cursor to end of document |
|
||||
| Ctrl+L | Jump to a line in the file (prompts with #) |
|
||||
| Ctrl+W | Cycle between splits in the current tab (use `> vsplit` or `> hsplit` to create a split) |
|
||||
| Ctrl-Home or Ctrl-UpArrow | Move cursor to start of document |
|
||||
| Ctrl-End or Ctrl-DownArrow | Move cursor to end of document |
|
||||
| Ctrl-l | Jump to a line in the file (prompts with #) |
|
||||
| Ctrl-w | Cycle between splits in the current tab (use `> vsplit` or `> hsplit` to create a split) |
|
||||
|
||||
### Tabs
|
||||
|
||||
| Key | Description of function |
|
||||
|-------- |------------------------- |
|
||||
| Ctrl+T | Open a new tab |
|
||||
| Alt+, | Previous tab |
|
||||
| Alt+. | Next tab |
|
||||
| Ctrl-t | Open a new tab |
|
||||
| Alt-, | Previous tab |
|
||||
| Alt-. | Next tab |
|
||||
|
||||
### Find Operations
|
||||
|
||||
| Key | Description of function |
|
||||
|---------- |------------------------------------------ |
|
||||
| Ctrl+F | Find (opens prompt) |
|
||||
| Ctrl+N | Find next instance of current search |
|
||||
| Ctrl+P | Find previous instance of current search |
|
||||
| Ctrl-f | Find (opens prompt) |
|
||||
| Ctrl-n | Find next instance of current search |
|
||||
| Ctrl-p | Find previous instance of current search |
|
||||
|
||||
### File Operations
|
||||
|
||||
| Key | Description of function |
|
||||
|---------- |------------------------------------------------------------------ |
|
||||
| Ctrl+Q | Close current file (quits micro if this is the last file open) |
|
||||
| Ctrl+O | Open a file (prompts for filename) |
|
||||
| Ctrl+S | Save current file |
|
||||
| Ctrl-q | Close current file (quits micro if this is the last file open) |
|
||||
| Ctrl-o | Open a file (prompts for filename) |
|
||||
| Ctrl-s | Save current file |
|
||||
|
||||
### Text operations
|
||||
|
||||
| Key | Description of function |
|
||||
|------------------------------------ |------------------------------------------ |
|
||||
| Ctrl(Alt on Mac)+Shift+RightArrow | Select word right |
|
||||
| Ctrl(Alt on Mac)+Shift+LeftArrow | Select word left |
|
||||
| Alt(Ctrl on Mac)+Shift+LeftArrow | Select to start of current line |
|
||||
| Alt(Ctrl on Mac)+Shift+RightArrow | Select to end of current line |
|
||||
| Shift+Home | Select to start of current line |
|
||||
| Shift+End | Select to end of current line |
|
||||
| Ctrl+Shift+UpArrow | Select to start of file |
|
||||
| Ctrl+Shift+DownArrow | Select to end of file |
|
||||
| Ctrl+X | Cut selected text |
|
||||
| Ctrl+C | Copy selected text |
|
||||
| Ctrl+V | Paste |
|
||||
| Ctrl+K | Cut current line |
|
||||
| Ctrl+D | Duplicate current line |
|
||||
| Ctrl+Z | Undo |
|
||||
| Ctrl+Y | Redo |
|
||||
| Alt+UpArrow | Move current line or selected lines up |
|
||||
| Alt+DownArrow | Move current line of selected lines down |
|
||||
| Alt+Backspace or Alt+Ctrl+H | Delete word left |
|
||||
| Ctrl+A | Select all |
|
||||
| Ctrl(Alt on Mac)-Shift-RightArrow | Select word right |
|
||||
| Ctrl(Alt on Mac)-Shift-LeftArrow | Select word left |
|
||||
| Alt(Ctrl on Mac)-Shift-LeftArrow | Select to start of current line |
|
||||
| Alt(Ctrl on Mac)-Shift-RightArrow | Select to end of current line |
|
||||
| Shift-Home | Select to start of current line |
|
||||
| Shift-End | Select to end of current line |
|
||||
| Ctrl-Shift-UpArrow | Select to start of file |
|
||||
| Ctrl-Shift-DownArrow | Select to end of file |
|
||||
| Ctrl-x | Cut selected text |
|
||||
| Ctrl-c | Copy selected text |
|
||||
| Ctrl-v | Paste |
|
||||
| Ctrl-k | Cut current line |
|
||||
| Ctrl-d | Duplicate current line |
|
||||
| Ctrl-z | Undo |
|
||||
| Ctrl-y | Redo |
|
||||
| Alt-UpArrow | Move current line or selected lines up |
|
||||
| Alt-DownArrow | Move current line of selected lines down |
|
||||
| Alt-Backspace or Alt-Ctrl-h | Delete word left |
|
||||
| Ctrl-a | Select all |
|
||||
|
||||
### Macros
|
||||
|
||||
| Key | Description of function |
|
||||
|---------- |---------------------------------------------------------------------------------- |
|
||||
| Ctrl+U | Toggle macro recording (press Ctrl+U to start recording and press again to stop) |
|
||||
| Ctrl+J | Run latest recorded macro |
|
||||
| Ctrl-u | Toggle macro recording (press Ctrl-u to start recording and press again to stop) |
|
||||
| Ctrl-j | Run latest recorded macro |
|
||||
|
||||
### Multiple cursors
|
||||
|
||||
| Key | Description of function |
|
||||
|------------------ |---------------------------------------------------------------------------------------------- |
|
||||
| Alt+N | Create new multiple cursor from selection (will select current word if no current selection) |
|
||||
| AltShiftUp | Spawn a new cursor on the line above the current one |
|
||||
| AltShiftDown | Spawn a new cursor on the line below the current one |
|
||||
| Alt+P | Remove latest multiple cursor |
|
||||
| Alt+C | Remove all multiple cursors (cancel) |
|
||||
| Alt+X | Skip multiple cursor selection |
|
||||
| Alt+M | Spawn a new cursor at the beginning of every line in the current selection |
|
||||
| Ctrl+MouseLeft | Place a multiple cursor at any location |
|
||||
| Alt-n | Create new multiple cursor from selection (will select current word if no current selection) |
|
||||
| Alt-Shift-Up | Spawn a new cursor on the line above the current one |
|
||||
| Alt-Shift-Down | Spawn a new cursor on the line below the current one |
|
||||
| Alt-p | Remove latest multiple cursor |
|
||||
| Alt-c | Remove all multiple cursors (cancel) |
|
||||
| Alt-x | Skip multiple cursor selection |
|
||||
| Alt-m | Spawn a new cursor at the beginning of every line in the current selection |
|
||||
| Ctrl-MouseLeft | Place a multiple cursor at any location |
|
||||
|
||||
### Other
|
||||
|
||||
| Key | Description of function |
|
||||
|---------- |-------------------------------------------------------------------------------------- |
|
||||
| Ctrl+G | Open help file |
|
||||
| Ctrl+H | Backspace (old terminals do not support the backspace key and use Ctrl+H instead) |
|
||||
| Ctrl+R | Toggle the line number ruler |
|
||||
| Ctrl-g | Open help file |
|
||||
| Ctrl-h | Backspace (old terminals do not support the backspace key and use Ctrl+H instead) |
|
||||
| Ctrl-r | Toggle the line number ruler |
|
||||
|
||||
### Emacs style actions
|
||||
|
||||
| Key | Description of function |
|
||||
|---------- |-------------------------- |
|
||||
| Alt+F | Next word |
|
||||
| Alt+B | Previous word |
|
||||
| Alt+A | Move to start of line |
|
||||
| Alt+E | Move to end of line |
|
||||
| Alt-f | Next word |
|
||||
| Alt-b | Previous word |
|
||||
| Alt-a | Move to start of line |
|
||||
| Alt-e | Move to end of line |
|
||||
|
||||
### Function keys.
|
||||
|
||||
|
||||
@@ -73,6 +73,12 @@ You can also bind a key to execute a command in command mode (see
|
||||
}
|
||||
```
|
||||
|
||||
**Note for macOS**: By default, macOS terminals do not forward alt events and
|
||||
instead insert unicode characters. To fix this, do the following:
|
||||
|
||||
* iTerm2: select `Esc+` for `Left Option Key` in `Preferences->Profiles->Keys`.
|
||||
* Terminal.app: Enable `Use Option key as Meta key` in `Preferences->Profiles->Keyboard`.
|
||||
|
||||
Now when you press `Alt-p` the `pwd` command will be executed which will show
|
||||
your working directory in the infobar.
|
||||
|
||||
@@ -162,6 +168,8 @@ SelectUp
|
||||
SelectDown
|
||||
SelectLeft
|
||||
SelectRight
|
||||
SelectToStartOfText
|
||||
SelectToStartOfTextToggle
|
||||
WordRight
|
||||
WordLeft
|
||||
SelectWordRight
|
||||
@@ -183,11 +191,13 @@ Save
|
||||
SaveAll
|
||||
SaveAs
|
||||
Find
|
||||
FindLiteral
|
||||
FindNext
|
||||
FindPrevious
|
||||
Undo
|
||||
Redo
|
||||
Copy
|
||||
CopyLine
|
||||
Cut
|
||||
CutLine
|
||||
DuplicateLine
|
||||
@@ -209,6 +219,8 @@ HalfPageUp
|
||||
HalfPageDown
|
||||
StartOfLine
|
||||
EndOfLine
|
||||
StartOfText
|
||||
StartOfTextToggle
|
||||
ParagraphPrevious
|
||||
ParagraphNext
|
||||
ToggleHelp
|
||||
@@ -245,6 +257,9 @@ 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)
|
||||
|
||||
```
|
||||
@@ -410,21 +425,21 @@ conventions for text editing defaults.
|
||||
"ShiftDown": "SelectDown",
|
||||
"ShiftLeft": "SelectLeft",
|
||||
"ShiftRight": "SelectRight",
|
||||
"AltLeft": "WordLeft",
|
||||
"AltRight": "WordRight",
|
||||
"AltLeft": "WordLeft", (Mac)
|
||||
"AltRight": "WordRight", (Mac)
|
||||
"AltUp": "MoveLinesUp",
|
||||
"AltDown": "MoveLinesDown",
|
||||
"CtrlShiftRight": "SelectWordRight",
|
||||
"CtrlShiftLeft": "SelectWordLeft",
|
||||
"AltLeft": "StartOfLine",
|
||||
"AltLeft": "StartOfTextToggle",
|
||||
"AltRight": "EndOfLine",
|
||||
"AltShiftRight": "SelectWordRight", (Mac)
|
||||
"AltShiftLeft": "SelectWordLeft", (Mac)
|
||||
"CtrlLeft": "StartOfText", (Mac)
|
||||
"CtrlRight": "EndOfLine", (Mac)
|
||||
"AltShiftLeft": "SelectToStartOfLine",
|
||||
"CtrlShiftLeft": "SelectToStartOfText", (Mac)
|
||||
"ShiftHome": "SelectToStartOfLine",
|
||||
"AltShiftLeft": "SelectToStartOfTextToggle",
|
||||
"CtrlShiftLeft": "SelectToStartOfTextToggle", (Mac)
|
||||
"ShiftHome": "SelectToStartOfTextToggle",
|
||||
"AltShiftRight": "SelectToEndOfLine",
|
||||
"CtrlShiftRight": "SelectToEndOfLine", (Mac)
|
||||
"ShiftEnd": "SelectToEndOfLine",
|
||||
@@ -448,7 +463,7 @@ conventions for text editing defaults.
|
||||
"CtrlP": "FindPrevious",
|
||||
"CtrlZ": "Undo",
|
||||
"CtrlY": "Redo",
|
||||
"CtrlC": "Copy",
|
||||
"CtrlC": "CopyLine|Copy",
|
||||
"CtrlX": "Cut",
|
||||
"CtrlK": "CutLine",
|
||||
"CtrlD": "DuplicateLine",
|
||||
@@ -457,7 +472,7 @@ conventions for text editing defaults.
|
||||
"CtrlT": "AddTab",
|
||||
"Alt,": "PreviousTab",
|
||||
"Alt.": "NextTab",
|
||||
"Home": "StartOfLine",
|
||||
"Home": "StartOfText",
|
||||
"End": "EndOfLine",
|
||||
"CtrlHome": "CursorStart",
|
||||
"CtrlEnd": "CursorEnd",
|
||||
|
||||
@@ -80,6 +80,21 @@ 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/.
|
||||
|
||||
@@ -102,12 +117,15 @@ 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.
|
||||
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.
|
||||
|
||||
default value: `unix`
|
||||
|
||||
@@ -163,7 +181,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
|
||||
@@ -172,6 +190,16 @@ 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.
|
||||
@@ -199,6 +227,12 @@ 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/`
|
||||
|
||||
@@ -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 == utf8.RuneCountInString(curLine) or not uutil.IsWordChar(charAt(curLine, bp.Cursor.X+1)) then
|
||||
if bp.Cursor.X == uutil.CharacterCountInString(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
|
||||
|
||||
@@ -6,23 +6,58 @@ local buffer = import("micro/buffer")
|
||||
|
||||
local ft = {}
|
||||
|
||||
ft["apacheconf"] = "# %s"
|
||||
ft["bat"] = ":: %s"
|
||||
ft["c"] = "// %s"
|
||||
ft["c++"] = "// %s"
|
||||
ft["cmake"] = "# %s"
|
||||
ft["conf"] = "# %s"
|
||||
ft["crystal"] = "# %s"
|
||||
ft["css"] = "/* %s */"
|
||||
ft["d"] = "// %s"
|
||||
ft["dart"] = "// %s"
|
||||
ft["dockerfile"] = "# %s"
|
||||
ft["elm"] = "-- %s"
|
||||
ft["fish"] = "# %s"
|
||||
ft["gdscript"] = "# %s"
|
||||
ft["glsl"] = "// %s"
|
||||
ft["go"] = "// %s"
|
||||
ft["python"] = "# %s"
|
||||
ft["python3"] = "# %s"
|
||||
ft["haskell"] = "-- %s"
|
||||
ft["html"] = "<!-- %s -->"
|
||||
ft["ini"] = "; %s"
|
||||
ft["java"] = "// %s"
|
||||
ft["javascript"] = "// %s"
|
||||
ft["jinja2"] = "{# %s #}"
|
||||
ft["julia"] = "# %s"
|
||||
ft["kotlin"] = "// %s"
|
||||
ft["lua"] = "-- %s"
|
||||
ft["markdown"] = "<!-- %s -->"
|
||||
ft["nginx"] = "# %s"
|
||||
ft["nim"] = "# %s"
|
||||
ft["objc"] = "// %s"
|
||||
ft["pascal"] = "{ %s }"
|
||||
ft["perl"] = "# %s"
|
||||
ft["php"] = "// %s"
|
||||
ft["rust"] = "// %s"
|
||||
ft["shell"] = "# %s"
|
||||
ft["lua"] = "-- %s"
|
||||
ft["javascript"] = "// %s"
|
||||
ft["pony"] = "// %s"
|
||||
ft["powershell"] = "# %s"
|
||||
ft["proto"] = "// %s"
|
||||
ft["python"] = "# %s"
|
||||
ft["python3"] = "# %s"
|
||||
ft["ruby"] = "# %s"
|
||||
ft["d"] = "// %s"
|
||||
ft["rust"] = "// %s"
|
||||
ft["scala"] = "// %s"
|
||||
ft["shell"] = "# %s"
|
||||
ft["sql"] = "-- %s"
|
||||
ft["swift"] = "// %s"
|
||||
ft["tex"] = "% %s"
|
||||
ft["toml"] = "# %s"
|
||||
ft["twig"] = "{# %s #}"
|
||||
ft["v"] = "// %s"
|
||||
ft["xml"] = "<!-- %s -->"
|
||||
ft["yaml"] = "# %s"
|
||||
ft["zig"] = "// %s"
|
||||
ft["zscript"] = "// %s"
|
||||
ft["zsh"] = "# %s"
|
||||
|
||||
function onBufferOpen(buf)
|
||||
if buf.Settings["commenttype"] == nil then
|
||||
@@ -37,7 +72,7 @@ end
|
||||
function commentLine(bp, lineN)
|
||||
local line = bp.Buf:Line(lineN)
|
||||
local commentType = bp.Buf.Settings["commenttype"]
|
||||
local commentRegex = "^%s*" .. commentType:gsub("%*", "%*"):gsub("%-", "%-"):gsub("%.", "%."):gsub("%+", "%+"):gsub("%]", "%]"):gsub("%[", "%["):gsub("%%s", "(.*)")
|
||||
local commentRegex = "^%s*" .. commentType:gsub("%%","%%%%"):gsub("%$","%$"):gsub("%)","%)"):gsub("%(","%("):gsub("%?","%?"):gsub("%*", "%*"):gsub("%-", "%-"):gsub("%.", "%."):gsub("%+", "%+"):gsub("%]", "%]"):gsub("%[", "%["):gsub("%%%%s", "(.*)")
|
||||
local sel = -bp.Cursor.CurSelection
|
||||
local curpos = -bp.Cursor.Loc
|
||||
local index = string.find(commentType, "%%s") - 1
|
||||
@@ -97,7 +132,8 @@ function comment(bp, args)
|
||||
end
|
||||
|
||||
function trim(s)
|
||||
return (s:gsub("^%s*(.-)%s*$", "%1"))
|
||||
local trimmed = s:gsub("^%s*(.-)%s*$", "%1"):gsub("%%","%%%%")
|
||||
return trimmed
|
||||
end
|
||||
|
||||
function string.starts(String,Start)
|
||||
|
||||
@@ -23,23 +23,58 @@ selected.
|
||||
The comment type will be auto detected based on the filetype,
|
||||
but it is only available for certain filetypes:
|
||||
|
||||
* apacheconf: `# %s`
|
||||
* bat: `:: %s`
|
||||
* c: `// %s`
|
||||
* c++: `// %s`
|
||||
* cmake: `# %s`
|
||||
* conf: `# %s`
|
||||
* crystal: `# %s`
|
||||
* css: `/* %s */`
|
||||
* d: `// %s`
|
||||
* dart: `// %s`
|
||||
* dockerfile: `# %s`
|
||||
* elm: `-- %s`
|
||||
* fish: `# %s`
|
||||
* gdscript: `# %s`
|
||||
* glsl: `// %s`
|
||||
* go: `// %s`
|
||||
* haskell: `-- %s`
|
||||
* html: `<!-- %s -->`
|
||||
* ini: `; %s`
|
||||
* java: `// %s`
|
||||
* javascript: `// %s`
|
||||
* jinja2: `{# %s #}`
|
||||
* julia: `# %s`
|
||||
* kotlin: `// %s`
|
||||
* lua: `-- %s`
|
||||
* markdown: `<!-- %s -->`
|
||||
* nginx: `# %s`
|
||||
* nim: `# %s`
|
||||
* objc: `// %s`
|
||||
* pascal: `{ %s }`
|
||||
* perl: `# %s`
|
||||
* php: `// %s`
|
||||
* pony: `// %s`
|
||||
* powershell: `# %s`
|
||||
* proto: `// %s`
|
||||
* python: `# %s`
|
||||
* python3: `# %s`
|
||||
* ruby: `# %s`
|
||||
* rust: `// %s`
|
||||
* scala: `// %s`
|
||||
* shell: `# %s`
|
||||
* sql: `-- %s`
|
||||
* swift: `// %s`
|
||||
* tex: `% %s`
|
||||
* toml: `# %s`
|
||||
* twig: `{# %s #}`
|
||||
* v: `// %s`
|
||||
* xml: `<!-- %s -->`
|
||||
* yaml: `# %s`
|
||||
* zig: `// %s`
|
||||
* zscript: `// %s`
|
||||
* zsh: `# %s`
|
||||
|
||||
If your filetype is not available here, you can simply modify
|
||||
the `commenttype` option:
|
||||
@@ -57,4 +92,3 @@ Or in your `settings.json`:
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -66,10 +66,11 @@ function init()
|
||||
end
|
||||
|
||||
makeLinter("gcc", "c", "gcc", {"-fsyntax-only", "-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m")
|
||||
makeLinter("gcc", "c++", "gcc", {"-fsyntax-only","-std=c++14", "-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m")
|
||||
makeLinter("g++", "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("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)
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
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:]]+$"
|
||||
@@ -12,6 +12,9 @@ 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:
|
||||
@@ -20,10 +23,23 @@ 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)"
|
||||
|
||||
|
||||
8
runtime/syntax/csx.yaml
Normal file
8
runtime/syntax/csx.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
filetype: csharp-script
|
||||
detect:
|
||||
filename: "\\.csx$"
|
||||
header: "^#!.*/(env +)?dotnet-script( |$)"
|
||||
|
||||
rules:
|
||||
- include: "csharp"
|
||||
- preproc: "\\B(\\#!|\\#[r|load|]+\\b)"
|
||||
@@ -26,7 +26,7 @@ rules:
|
||||
|
||||
# Diffs (i.e. git commit --verbose)
|
||||
- default:
|
||||
start: "^diff"
|
||||
start: "^diff --git"
|
||||
# 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
|
||||
|
||||
@@ -8,13 +8,14 @@ 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 type|primitive type|mutable struct\\b)"
|
||||
- statement: "\\b(abstract\\s+type|primitive\\s+type|mutable\\s+struct)\\b"
|
||||
# decorators
|
||||
- identifier.macro: "@[A-Za-z0-9_]+"
|
||||
# operators
|
||||
@@ -22,7 +23,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]+)*)\\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]+)*|Inf(16|32|64)?|NaN(16|32|64)?)\\b"
|
||||
|
||||
- constant.string: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^']){1}'"
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
filetype: python
|
||||
filetype: python2
|
||||
|
||||
detect:
|
||||
filename: "\\.py$"
|
||||
header: "^#!.*/(env +)?python( |$)"
|
||||
filename: "\\.py2$"
|
||||
header: "^#!.*/(env +)?python2$"
|
||||
|
||||
rules:
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
filename: python3
|
||||
filetype: python
|
||||
|
||||
detect:
|
||||
filename: "\\.py3$"
|
||||
header: "^#!.*/(env +)?python3$"
|
||||
filename: "\\.py(3)?$"
|
||||
header: "^#!.*/(env +)?python(3)?$"
|
||||
|
||||
rules:
|
||||
# built-in objects
|
||||
@@ -18,7 +18,7 @@ rules:
|
||||
# definitions
|
||||
- identifier: "def [a-zA-Z_0-9]+"
|
||||
# keywords
|
||||
- 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"
|
||||
- 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"
|
||||
# decorators
|
||||
- brightgreen: "@.*[(]"
|
||||
# operators
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
filetype: ruby
|
||||
|
||||
detect:
|
||||
filename: "\\.(rb|rake|gemspec)$|^(Gemfile|config.ru|Rakefile|Capfile|Vagrantfile|Guardfile)$"
|
||||
filename: "\\.(rb|rake|gemspec)$|^(Gemfile|config.ru|Rakefile|Capfile|Vagrantfile|Guardfile|Appfile|Fastfile|Pluginfile|Podfile)$"
|
||||
header: "^#!.*/(env +)?ruby( |$)"
|
||||
|
||||
rules:
|
||||
|
||||
60
runtime/syntax/sage.yaml
Normal file
60
runtime/syntax/sage.yaml
Normal file
@@ -0,0 +1,60 @@
|
||||
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: []
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
filetype: shell
|
||||
|
||||
detect:
|
||||
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( |$)"
|
||||
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( |$)"
|
||||
|
||||
rules:
|
||||
# Numbers
|
||||
|
||||
@@ -4,39 +4,53 @@ detect:
|
||||
filename: "\\.toml"
|
||||
|
||||
rules:
|
||||
- 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})"
|
||||
|
||||
# Punctuation
|
||||
- symbol: '[=,\.]'
|
||||
- symbol.brackets: '[{\[\]}]'
|
||||
# Strings
|
||||
- constant.string:
|
||||
start: "\""
|
||||
end: "\""
|
||||
skip: "\\\\."
|
||||
start: '"""'
|
||||
end: '\"{3,5}'
|
||||
skip: '\\.'
|
||||
rules:
|
||||
- constant.specialChar: "\\\\."
|
||||
|
||||
- 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.string:
|
||||
start: "'"
|
||||
end: "'"
|
||||
skip: "\\\\."
|
||||
rules:
|
||||
- constant.specialChar: "\\\\."
|
||||
|
||||
- constant.string:
|
||||
start: "`"
|
||||
end: "`"
|
||||
rules:
|
||||
- constant.specialChar: "\\\\."
|
||||
|
||||
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
|
||||
- comment:
|
||||
start: "#"
|
||||
end: "$"
|
||||
rules:
|
||||
- todo: "(TODO|XXX|FIXME):?"
|
||||
|
||||
|
||||
Submodule tools/go-bindata deleted from 9453701aa0
@@ -233,8 +233,6 @@ func main() {
|
||||
re := regexp.MustCompile(`[^\w]`)
|
||||
usedNames := map[string]bool{}
|
||||
|
||||
var b strings.Builder
|
||||
|
||||
for _, test := range tests {
|
||||
name := strings.Title(strings.ToLower(test.description))
|
||||
name = re.ReplaceAllLiteralString(name, "")
|
||||
@@ -253,15 +251,5 @@ func main() {
|
||||
usedNames[name] = true
|
||||
|
||||
fmt.Println(testToGoTest(test, name))
|
||||
|
||||
b.WriteString("Test")
|
||||
b.WriteString(name)
|
||||
b.WriteString("(nil)\n")
|
||||
}
|
||||
|
||||
fmt.Println("func BenchmarkBuffer(b *testing.B) {")
|
||||
fmt.Println("for i := 0; i < b.N; i++ {")
|
||||
fmt.Print(b.String())
|
||||
fmt.Println("}")
|
||||
fmt.Println("}")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user