mirror of
https://github.com/zyedidia/micro.git
synced 2026-04-01 15:47:12 +09:00
Compare commits
105 Commits
insert-per
...
buffer-uni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59e8f3aa3e | ||
|
|
53bda0cfa7 | ||
|
|
f059541e0d | ||
|
|
d78fe81e21 | ||
|
|
25b9342fbe | ||
|
|
70bcf9f618 | ||
|
|
8848388411 | ||
|
|
dff8b33e9c | ||
|
|
8a2048e7f6 | ||
|
|
0174d7dba4 | ||
|
|
e1827480c9 | ||
|
|
d8584d1ddb | ||
|
|
f0cdc3cabb | ||
|
|
2ef4f83358 | ||
|
|
a9120ce270 | ||
|
|
190d9d0609 | ||
|
|
cf3fdb344a | ||
|
|
b91242124c | ||
|
|
5ffc19f159 | ||
|
|
cc994b6241 | ||
|
|
087e7207f7 | ||
|
|
db32b84cd1 | ||
|
|
00006aa2b4 | ||
|
|
600d8558b2 | ||
|
|
4874823240 | ||
|
|
6a0e4b5564 | ||
|
|
b2d7c8c5d4 | ||
|
|
38f88ade60 | ||
|
|
8348cc8ec2 | ||
|
|
743d42e417 | ||
|
|
faa207907c | ||
|
|
9d1c489574 | ||
|
|
30ed25859a | ||
|
|
d2288c5f66 | ||
|
|
a07ee26b05 | ||
|
|
a7ce85d6f6 | ||
|
|
7c71995aaf | ||
|
|
357c4b0fcd | ||
|
|
0d4f85304b | ||
|
|
e18e41eb45 | ||
|
|
5519f053ac | ||
|
|
2f4b3b2a8c | ||
|
|
ea290e4fb5 | ||
|
|
8b414e6187 | ||
|
|
e7ef81ed97 | ||
|
|
12c286f9b1 | ||
|
|
7b5bc8fe37 | ||
|
|
bad78797bb | ||
|
|
bf1258578c | ||
|
|
6588f02f7b | ||
|
|
5e9c6375d0 | ||
|
|
7d47659481 | ||
|
|
dcd4bae96f | ||
|
|
4f628bf30b | ||
|
|
36e83a46e4 | ||
|
|
1a64ffb88b | ||
|
|
7c77927913 | ||
|
|
8224037080 | ||
|
|
d7e3fc99f1 | ||
|
|
feaf3951d2 | ||
|
|
399c629076 | ||
|
|
47ed7447f1 | ||
|
|
62a98ea3c5 | ||
|
|
0a9194b883 | ||
|
|
a938917b9b | ||
|
|
695d4c2b1b | ||
|
|
34724b941a | ||
|
|
8176e8c6f8 | ||
|
|
0d5b1cd64d | ||
|
|
9fd5b133ea | ||
|
|
432b57a070 | ||
|
|
ee55732be3 | ||
|
|
90304fb472 | ||
|
|
f6aec1af5f | ||
|
|
b77b61d677 | ||
|
|
05a0598f16 | ||
|
|
daa6f122a7 | ||
|
|
71f5f043fb | ||
|
|
f3eaf99665 | ||
|
|
c88c1b84da | ||
|
|
e1e310a96e | ||
|
|
d29b941be0 | ||
|
|
cde696915d | ||
|
|
185b8de17b | ||
|
|
d65285ee54 | ||
|
|
848bd1ba8c | ||
|
|
00205aa6a7 | ||
|
|
ecb9fd5a8a | ||
|
|
bdf9e6d3a4 | ||
|
|
3ed77dbb2e | ||
|
|
57a992c4a3 | ||
|
|
c63614213d | ||
|
|
b7a54fa74a | ||
|
|
63046ae909 | ||
|
|
af48e4b79b | ||
|
|
4e73d0779b | ||
|
|
6f424f3213 | ||
|
|
e110e93e0f | ||
|
|
8ddf335e68 | ||
|
|
de33eac058 | ||
|
|
aae0f4630e | ||
|
|
c46695bb57 | ||
|
|
a732d03b4d | ||
|
|
28267b9eb2 | ||
|
|
cad43914b0 |
2
.github/ISSUE_TEMPLATE
vendored
2
.github/ISSUE_TEMPLATE
vendored
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Specifications
|
## Specifications
|
||||||
|
|
||||||
You can use `micro -version` to get the commit hash.
|
<!-- You can use `micro -version` to get the commit hash. -->
|
||||||
|
|
||||||
Commit hash:
|
Commit hash:
|
||||||
OS:
|
OS:
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,4 +15,5 @@ tools/build-version
|
|||||||
tools/build-date
|
tools/build-date
|
||||||
tools/info-plist
|
tools/info-plist
|
||||||
tools/bindata
|
tools/bindata
|
||||||
|
tools/vscode-tests/
|
||||||
*.hdr
|
*.hdr
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2016-2017: Zachary Yedidia, et al.
|
Copyright (c) 2016-2020: Zachary Yedidia, et al.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|||||||
24
Makefile
24
Makefile
@@ -8,14 +8,19 @@ DATE = $(shell GOOS=$(shell go env GOHOSTOS) GOARCH=$(shell go env GOHOSTARCH) \
|
|||||||
ADDITIONAL_GO_LINKER_FLAGS = $(shell GOOS=$(shell go env GOHOSTOS) \
|
ADDITIONAL_GO_LINKER_FLAGS = $(shell GOOS=$(shell go env GOHOSTOS) \
|
||||||
GOARCH=$(shell go env GOHOSTARCH))
|
GOARCH=$(shell go env GOHOSTARCH))
|
||||||
GOBIN ?= $(shell go env GOPATH)/bin
|
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)' -X github.com/zyedidia/micro/internal/util.Debug=OFF
|
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
|
||||||
|
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
|
# Builds micro after checking dependencies but without updating the runtime
|
||||||
build:
|
build:
|
||||||
go build -ldflags "-s -w $(GOVARS) $(ADDITIONAL_GO_LINKER_FLAGS)" ./cmd/micro
|
go build -ldflags "-s -w $(GOVARS) $(ADDITIONAL_GO_LINKER_FLAGS)" ./cmd/micro
|
||||||
|
|
||||||
build-dbg:
|
build-dbg:
|
||||||
go build -ldflags "-s -w $(ADDITIONAL_GO_LINKER_FLAGS)" ./cmd/micro
|
go build -ldflags "-s -w $(ADDITIONAL_GO_LINKER_FLAGS) $(DEBUGVAR)" ./cmd/micro
|
||||||
|
|
||||||
|
build-tags: fetch-tags
|
||||||
|
go build -ldflags "-s -w $(GOVARS) $(ADDITIONAL_GO_LINKER_FLAGS)" ./cmd/micro
|
||||||
|
|
||||||
# Builds micro after building the runtime and checking dependencies
|
# Builds micro after building the runtime and checking dependencies
|
||||||
build-all: runtime build
|
build-all: runtime build
|
||||||
@@ -35,6 +40,9 @@ install-all: runtime install
|
|||||||
install-quick:
|
install-quick:
|
||||||
go install -ldflags "-s -w $(GOVARS) $(ADDITIONAL_GO_LINKER_FLAGS)" ./cmd/micro
|
go install -ldflags "-s -w $(GOVARS) $(ADDITIONAL_GO_LINKER_FLAGS)" ./cmd/micro
|
||||||
|
|
||||||
|
fetch-tags:
|
||||||
|
git fetch --tags
|
||||||
|
|
||||||
# Builds the runtime
|
# Builds the runtime
|
||||||
runtime:
|
runtime:
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
@@ -44,8 +52,20 @@ runtime:
|
|||||||
mv runtime.go internal/config
|
mv runtime.go internal/config
|
||||||
gofmt -w internal/config/runtime.go
|
gofmt -w internal/config/runtime.go
|
||||||
|
|
||||||
|
testgen:
|
||||||
|
mkdir -p tools/vscode-tests
|
||||||
|
cd tools/vscode-tests && \
|
||||||
|
curl --remote-name-all $(VSCODE_TESTS_BASE_URL){editableTextModelAuto,editableTextModel,model.line}.test.ts
|
||||||
|
tsc tools/vscode-tests/*.ts > /dev/null; true
|
||||||
|
go run tools/testgen.go tools/vscode-tests/*.js > buffer_generated_test.go
|
||||||
|
mv buffer_generated_test.go internal/buffer
|
||||||
|
gofmt -w internal/buffer/buffer_generated_test.go
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test ./internal/...
|
go test ./internal/...
|
||||||
|
|
||||||
|
bench:
|
||||||
|
go test -bench=. ./internal/...
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f micro
|
rm -f micro
|
||||||
|
|||||||
175
README.md
175
README.md
@@ -1,32 +1,35 @@
|
|||||||
# 
|
<img alt="micro logo" src="./assets/micro-logo.svg" width="500px"/>
|
||||||
|
|
||||||
[](https://travis-ci.org/zyedidia/micro)
|
[](https://travis-ci.org/zyedidia/micro)
|
||||||
[](https://goreportcard.com/report/github.com/zyedidia/micro)
|
[](https://goreportcard.com/report/github.com/zyedidia/micro)
|
||||||
[](https://gitter.im/zyedidia/micro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://github.com/zyedidia/micro/releases)
|
||||||
[](https://github.com/zyedidia/micro/blob/master/LICENSE)
|
[](https://github.com/zyedidia/micro/blob/master/LICENSE)
|
||||||
|
[](https://gitter.im/zyedidia/micro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
[](https://build.snapcraft.io/user/zyedidia/micro)
|
[](https://build.snapcraft.io/user/zyedidia/micro)
|
||||||
|
|
||||||
Micro is a terminal-based text editor that aims to be easy to use and intuitive, while also taking advantage of the full capabilities
|
**micro** is a terminal-based text editor that aims to be easy to use and intuitive, while also taking advantage of the capabilities
|
||||||
of modern terminals. It comes as one single, batteries-included, static binary with no dependencies, and you can download and use it right now.
|
of modern terminals. It comes as a single, batteries-included, static binary with no dependencies; you can download and use it right now!
|
||||||
|
|
||||||
As the name indicates, micro aims to be somewhat of a successor to the nano editor by being easy to install and use in a pinch, but micro also aims to be
|
As its name indicates, micro aims to be somewhat of a successor to the nano editor by being easy to install and use.
|
||||||
enjoyable to use full time, whether you work in the terminal because you prefer it (like me), or because you need to (over ssh).
|
It strives to be enjoyable as a full-time editor for people who prefer to work in a terminal, or those who regularly edit files over SSH.
|
||||||
|
|
||||||
Here is a picture of micro editing its source code.
|
Here is a picture of micro editing its source code.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
To see more screenshots of micro, showcasing all of the default colorschemes, see [here](http://zbyedidia.webfactional.com/micro/screenshots.html).
|
To see more screenshots of micro, showcasing some of the default color schemes, see [here](http://zbyedidia.webfactional.com/micro/screenshots.html).
|
||||||
|
|
||||||
You can also check out the website for Micro at https://micro-editor.github.io.
|
You can also check out the website for Micro at https://micro-editor.github.io.
|
||||||
|
|
||||||
# Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [Features](#features)
|
- [Features](#features)
|
||||||
- [Installation](#installation)
|
- [Installation](#installation)
|
||||||
- [Prebuilt binaries](#prebuilt-binaries)
|
- [Prebuilt binaries](#prebuilt-binaries)
|
||||||
- [Package Managers](#package-managers)
|
- [Package Managers](#package-managers)
|
||||||
- [Building from source](#building-from-source)
|
- [Building from source](#building-from-source)
|
||||||
- [MacOS terminal](#macos-terminal)
|
- [Fully static binary](#fully-static-binary)
|
||||||
|
- [macOS terminal](#macos-terminal)
|
||||||
- [Linux clipboard support](#linux-clipboard-support)
|
- [Linux clipboard support](#linux-clipboard-support)
|
||||||
- [Colors and syntax highlighting](#colors-and-syntax-highlighting)
|
- [Colors and syntax highlighting](#colors-and-syntax-highlighting)
|
||||||
- [Plan9, Cygwin, Mingw](#plan9-cygwin-mingw)
|
- [Plan9, Cygwin, Mingw](#plan9-cygwin-mingw)
|
||||||
@@ -36,35 +39,38 @@ You can also check out the website for Micro at https://micro-editor.github.io.
|
|||||||
|
|
||||||
- - -
|
- - -
|
||||||
|
|
||||||
# Features
|
## Features
|
||||||
|
|
||||||
* Easy to use and to install
|
- Easy to use and install.
|
||||||
* No dependencies or external files are needed -- just the binary you can download further down the page
|
- No dependencies or external files are needed — just the binary you can download further down the page.
|
||||||
* Multiple cursors
|
- Multiple cursors.
|
||||||
* Common keybindings (ctrl-s, ctrl-c, ctrl-v, ctrl-z...)
|
- 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
|
- Keybindings can be rebound to your liking.
|
||||||
* Sane defaults
|
- Sane defaults.
|
||||||
* You shouldn't have to configure much out of the box (and it is extremely easy to configure)
|
- You shouldn't have to configure much out of the box (and it is extremely easy to configure).
|
||||||
* Splits and tabs
|
- Splits and tabs.
|
||||||
* Nano-like menu to help you remember the keybindings
|
- nano-like menu to help you remember the keybindings.
|
||||||
* Extremely good mouse support
|
- 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
|
- 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)
|
- 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)
|
- Plugin system (plugins are written in Lua).
|
||||||
* Persistent undo
|
- micro has a built-in plugin manager to automatically install, remove, and update plugins.
|
||||||
* Automatic linting and error notifications
|
- Built-in diff gutter
|
||||||
* Syntax highlighting (for over [120 languages](runtime/syntax)!)
|
- Simple autocompletion
|
||||||
* Colorscheme support
|
- Persistent undo.
|
||||||
* By default, micro comes with 16, 256, and true color themes.
|
- Automatic linting and error notifications
|
||||||
* True color support (set the `MICRO_TRUECOLOR` environment variable to 1 to enable it)
|
- Syntax highlighting for over [130 languages](runtime/syntax).
|
||||||
* Copy and paste with the system clipboard
|
- Color scheme support.
|
||||||
* Small and simple
|
- By default, micro comes with 16, 256, and true color themes.
|
||||||
* Easily configurable
|
- True color support (set the `MICRO_TRUECOLOR` environment variable to 1 to enable it).
|
||||||
* Macros
|
- Copy and paste with the system clipboard.
|
||||||
* Common editor things such as undo/redo, line numbers, Unicode support, softwrap...
|
- Small and simple.
|
||||||
|
- Easily configurable.
|
||||||
|
- Macros.
|
||||||
|
- Common editor features such as undo/redo, line numbers, Unicode support, soft wrapping, …
|
||||||
|
|
||||||
# Installation
|
## Installation
|
||||||
|
|
||||||
To install micro, you can download a [prebuilt binary](https://github.com/zyedidia/micro/releases), or you can build it from source.
|
To install micro, you can download a [prebuilt binary](https://github.com/zyedidia/micro/releases), or you can build it from source.
|
||||||
|
|
||||||
@@ -79,19 +85,19 @@ Download the binary from the [releases](https://github.com/zyedidia/micro/releas
|
|||||||
On that page you'll see the nightly release, which contains binaries for micro which are built every night,
|
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.
|
and you'll see all the stable releases with the corresponding binaries.
|
||||||
|
|
||||||
If you'd like to see more information after installing micro, run `micro -version`.
|
Running `micro -version` will give you the version information.
|
||||||
|
|
||||||
### Installation script
|
### Installation script
|
||||||
|
|
||||||
There is a great script which can install micro for you by downloading the latest prebuilt binary. You can find it at https://getmic.ro (the github repo for it is [here](https://github.com/benweissmann/getmic.ro)).
|
There is a script which can install micro for you by downloading the latest prebuilt binary. You can find it at <https://getmic.ro>.
|
||||||
|
|
||||||
Then you can easily install micro:
|
Then you can easily install micro:
|
||||||
|
|
||||||
$ curl https://getmic.ro | bash
|
```bash
|
||||||
|
curl https://getmic.ro | bash
|
||||||
|
```
|
||||||
|
|
||||||
The script will install the micro binary to the current directory.
|
The script will install the micro binary to the current directory. See its [GitHub repository](https://github.com/benweissmann/getmic.ro) for more information.
|
||||||
|
|
||||||
See the [Github page](https://github.com/benweissmann/getmic.ro) for more information.
|
|
||||||
|
|
||||||
### Package managers
|
### Package managers
|
||||||
|
|
||||||
@@ -101,13 +107,18 @@ You can install micro using Homebrew on Mac:
|
|||||||
brew install micro
|
brew install micro
|
||||||
```
|
```
|
||||||
|
|
||||||
On Debian Linux, you can install micro through [snap](https://snapcraft.io/docs/core/install)
|
On Linux, you can install micro through [snap](https://snapcraft.io/docs/core/install)
|
||||||
|
|
||||||
```
|
```
|
||||||
snap install micro --classic
|
snap install micro --classic
|
||||||
```
|
```
|
||||||
|
|
||||||
Homebrew and snap are the two "officially" maintained package manager distributions of micro.
|
On Debian `unstable | testing | buster-backports` and Ubuntu `focal` (20.04), micro is available
|
||||||
|
via `apt`:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo apt install micro
|
||||||
|
```
|
||||||
|
|
||||||
Micro is also available through other package managers on Linux such as AUR, Nix, and package managers
|
Micro is also available through other package managers on Linux such as AUR, Nix, and package managers
|
||||||
for other operating systems:
|
for other operating systems:
|
||||||
@@ -137,55 +148,67 @@ anywhere you like (for example `/usr/local/bin`).
|
|||||||
The command `make install` will install the binary to `$GOPATH/bin` or `$GOBIN`.
|
The command `make install` will install the binary to `$GOPATH/bin` or `$GOBIN`.
|
||||||
|
|
||||||
You can install directly with `go get` (`go get github.com/zyedidia/micro/cmd/micro`) but this isn't
|
You can install directly with `go get` (`go get github.com/zyedidia/micro/cmd/micro`) but this isn't
|
||||||
recommended because it doesn't build micro with version information, and doesn't disable debug mode.
|
recommended because it doesn't build micro with version information (necessary for the plugin manager),
|
||||||
|
and doesn't disable debug mode.
|
||||||
|
|
||||||
### MacOS terminal
|
### Fully static binary
|
||||||
|
|
||||||
If you are using MacOS, you should consider using [iTerm2](http://iterm2.com/) instead of the default Mac terminal. The iTerm2 terminal has much better mouse support as well as better handling of key events. For best keybinding behavior, choose `xterm defaults` under `Preferences->Profiles->Keys->Load Preset`. The newest versions also support true color.
|
By default, the micro binary will dynamically link with core system libraries (this is generally
|
||||||
|
recommended for security and portability). However, there is a fully static prebuilt binary that
|
||||||
|
is provided for amd64 as `linux-static.tar.gz`, and to build a fully static binary from source, run
|
||||||
|
|
||||||
|
```
|
||||||
|
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 still insist on using the default Mac terminal, be sure to set `Use Option key as Meta key` under
|
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>.
|
`Preferences->Profiles->Keyboard` to use <kbd>option</kbd> as <kbd>alt</kbd>.
|
||||||
|
|
||||||
### Linux clipboard support
|
### Linux clipboard support
|
||||||
|
|
||||||
On Linux, clipboard support requires the 'xclip' or 'xsel' commands to be installed.
|
On Linux, clipboard support requires:
|
||||||
|
|
||||||
For Ubuntu:
|
- On X11, the `xclip` or `xsel` commands (for Ubuntu: `sudo apt install xclip`)
|
||||||
|
- On Wayland, the `wl-clipboard` command
|
||||||
|
|
||||||
```sh
|
If you don't have these commands, micro will use an internal clipboard for copy and paste, but it won't work with external applications.
|
||||||
sudo apt-get install xclip
|
|
||||||
```
|
|
||||||
|
|
||||||
If you don't have xclip or xsel, micro will use an internal clipboard for copy and paste, but it won't work with external applications.
|
|
||||||
|
|
||||||
### Colors and syntax highlighting
|
### Colors and syntax highlighting
|
||||||
|
|
||||||
If you open micro and it doesn't seem like syntax highlighting is working, this is probably because
|
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 colors. Try changing the colorscheme to `simple`
|
you are using a terminal which does not support 256 color mode. Try changing the color scheme to `simple`
|
||||||
by pressing CtrlE 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
|
If you are using the default Ubuntu terminal, to enable 256 make sure your `TERM` variable is set
|
||||||
to `xterm-256color`.
|
to `xterm-256color`.
|
||||||
|
|
||||||
Many older Windows terminals don't support more than 16 colors, which means
|
Many of the Windows terminals don't support more than 16 colors, which means
|
||||||
that micro's default colorscheme won't look very good. You can either set
|
that micro's default color scheme won't look very good. You can either set
|
||||||
the colorscheme to `simple`, or download a better terminal emulator, like
|
the color scheme to `simple`, or download and configure a better terminal emulator
|
||||||
mintty. However, if you are on a recent version of Windows 10, the default
|
than the Windows default.
|
||||||
`cmd.exe` should do fine.
|
|
||||||
|
|
||||||
### Plan9, Cygwin, Mingw
|
### Cygwin, Mingw, Plan9
|
||||||
|
|
||||||
These platforms are unfortunately not supported.
|
Cygwin, Mingw, and Plan9 are unfortunately not officially supported. In Cygwin and Mingw, micro will often work when run using
|
||||||
|
the `winpty` utility:
|
||||||
|
|
||||||
|
```
|
||||||
|
winpty micro.exe ...
|
||||||
|
```
|
||||||
|
|
||||||
Micro uses the amazing [tcell library](https://github.com/gdamore/tcell), but this
|
Micro uses the amazing [tcell library](https://github.com/gdamore/tcell), but this
|
||||||
means that micro is restricted to the platforms tcell supports. As a result, micro does not support
|
means that micro is restricted to the platforms tcell supports. As a result, micro does not support
|
||||||
Plan9, and Cygwin (although this may change in the future). Micro also doesn't support NaCl (but NaCl is deprecated anyways).
|
Plan9, and Cygwin (although this may change in the future). Micro also doesn't support NaCl (which is deprecated anyway).
|
||||||
|
|
||||||
# Usage
|
## Usage
|
||||||
|
|
||||||
Once you have built the editor, simply start it by running `micro path/to/file.txt` or simply `micro` to open an empty buffer.
|
Once you have built the editor, start it by running `micro path/to/file.txt` or `micro` to open an empty buffer.
|
||||||
|
|
||||||
Micro also supports creating buffers from `stdin`:
|
micro also supports creating buffers from `stdin`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
ifconfig | micro
|
ifconfig | micro
|
||||||
@@ -197,22 +220,22 @@ You can also use the mouse to manipulate the text. Simply clicking and dragging
|
|||||||
will select text. You can also double click to enable word selection, and triple
|
will select text. You can also double click to enable word selection, and triple
|
||||||
click to enable line selection.
|
click to enable line selection.
|
||||||
|
|
||||||
# Documentation and Help
|
## Documentation and Help
|
||||||
|
|
||||||
Micro has a built-in help system which you can access by pressing `Ctrl-E` 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:
|
view the help files here:
|
||||||
|
|
||||||
* [main help](https://github.com/zyedidia/micro/tree/master/runtime/help/help.md)
|
- [main help](https://github.com/zyedidia/micro/tree/master/runtime/help/help.md)
|
||||||
* [keybindings](https://github.com/zyedidia/micro/tree/master/runtime/help/keybindings.md)
|
- [keybindings](https://github.com/zyedidia/micro/tree/master/runtime/help/keybindings.md)
|
||||||
* [commands](https://github.com/zyedidia/micro/tree/master/runtime/help/commands.md)
|
- [commands](https://github.com/zyedidia/micro/tree/master/runtime/help/commands.md)
|
||||||
* [colors](https://github.com/zyedidia/micro/tree/master/runtime/help/colors.md)
|
- [colors](https://github.com/zyedidia/micro/tree/master/runtime/help/colors.md)
|
||||||
* [options](https://github.com/zyedidia/micro/tree/master/runtime/help/options.md)
|
- [options](https://github.com/zyedidia/micro/tree/master/runtime/help/options.md)
|
||||||
* [plugins](https://github.com/zyedidia/micro/tree/master/runtime/help/plugins.md)
|
- [plugins](https://github.com/zyedidia/micro/tree/master/runtime/help/plugins.md)
|
||||||
|
|
||||||
I also recommend reading the [tutorial](https://github.com/zyedidia/micro/tree/master/runtime/help/tutorial.md) for
|
I also recommend reading the [tutorial](https://github.com/zyedidia/micro/tree/master/runtime/help/tutorial.md) for
|
||||||
a brief introduction to the more powerful configuration features micro offers.
|
a brief introduction to the more powerful configuration features micro offers.
|
||||||
|
|
||||||
# Contributing
|
## Contributing
|
||||||
|
|
||||||
If you find any bugs, please report them! I am also happy to accept pull requests from anyone.
|
If you find any bugs, please report them! I am also happy to accept pull requests from anyone.
|
||||||
|
|
||||||
|
|||||||
BIN
assets/logo.png
BIN
assets/logo.png
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -1,63 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
id="svg3336"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.91 r13725"
|
|
||||||
width="128"
|
|
||||||
height="128"
|
|
||||||
viewBox="0 0 128 128"
|
|
||||||
sodipodi:docname="logo.svg">
|
|
||||||
<metadata
|
|
||||||
id="metadata3342">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<defs
|
|
||||||
id="defs3340" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1"
|
|
||||||
objecttolerance="10"
|
|
||||||
gridtolerance="10"
|
|
||||||
guidetolerance="10"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:window-width="1355"
|
|
||||||
inkscape:window-height="717"
|
|
||||||
id="namedview3338"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="1.6243169"
|
|
||||||
inkscape:cx="111.32302"
|
|
||||||
inkscape:cy="30.538264"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="svg3336" />
|
|
||||||
<path
|
|
||||||
style="fill:#2e3192;fill-opacity:1"
|
|
||||||
d="m 56.1,127.32358 c -13.68932,-1.70993 -27.156628,-8.3544 -37.112903,-18.31068 -25.0687936,-25.068788 -25.0687936,-65.95701 0,-91.025803 25.068793,-25.0687936 65.957015,-25.0687936 91.025803,0 25.0688,25.068793 25.0688,65.957015 0,91.025803 C 95.87457,123.15123 76.198116,129.83404 56.1,127.32358 Z"
|
|
||||||
id="path3364"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:#ffffff"
|
|
||||||
d="m 40.756452,106.01908 c 1.442831,-1.83426 1.55476,-4.09687 0.414499,-8.37899 -0.678184,-2.546844 -0.684604,-4.05591 -0.03829,-9 1.276867,-9.767604 4.483143,-23.040636 5.565559,-23.039766 0.220979,1.74e-4 0.417725,2.092674 0.437213,4.65 0.04167,5.468298 1.558564,9.06891 4.638769,11.010942 2.551646,1.608774 9.15365,1.329324 12.80399,-0.541974 3.245124,-1.663572 7.649064,-6.112434 9.850956,-9.951438 L 76.188736,67.7 l 0.0054,3.922866 c 0.0042,2.867148 0.36894,4.642788 1.355628,6.59796 1.532058,3.035856 3.323226,4.15755 6.659322,4.17033 5.192928,0.01986 9.07014,-3.668676 10.866768,-10.338036 0.98277,-3.64821 1.064448,-11.21265 0.09235,-8.55312 -3.025218,8.276592 -4.468212,9.893562 -9.238056,10.351884 -2.629152,0.25263 -3.177804,0.08883 -4.921776,-1.469412 -1.609044,-1.437678 -2.016072,-2.308416 -2.258508,-4.8315 -0.262884,-2.73585 0.105942,-4.06497 3.32007,-11.964365 C 88.28388,40.315087 89.33625,35.536248 87,33.2 c -1.559352,-1.559353 -3.62787,-1.522741 -5.691792,0.10074 -2.295762,1.805846 -3.105984,4.070756 -5.14293,14.376662 -2.464164,12.46744 -6.525822,20.297092 -12.62193,24.331306 C 59.052142,74.98085 52.704914,73.6403 50.637191,69.282896 49.19967,66.253544 49.857706,62.552972 53.387813,53.814319 56.613526,45.829186 58.8,38.711369 58.8,36.195564 c 0,-4.161283 -4.366993,-5.665719 -7.364438,-2.537061 -2.183558,2.279144 -3.117251,5.256959 -4.280897,13.653016 -0.547956,3.953665 -1.259292,9.010489 -1.580746,11.237387 -0.321454,2.226896 -2.083918,8.706896 -3.916587,14.400002 -4.33165,13.456074 -6.85029,23.184822 -7.273674,28.096022 -0.325586,3.77675 -0.269352,4.00056 1.319044,5.25 2.187498,1.72068 3.541408,1.64679 5.05375,-0.27585 z"
|
|
||||||
id="path3362"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.6 KiB |
70
assets/micro-logo.svg
Normal file
70
assets/micro-logo.svg
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
id="Layer_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 299.89999 103.2"
|
||||||
|
enable-background="new 0 0 960 560"
|
||||||
|
xml:space="preserve"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="micro-logo.svg"
|
||||||
|
width="299.89999"
|
||||||
|
height="103.2"><metadata
|
||||||
|
id="metadata21"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs19" /><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1237"
|
||||||
|
inkscape:window-height="867"
|
||||||
|
id="namedview17"
|
||||||
|
showgrid="false"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:zoom="1.1416667"
|
||||||
|
inkscape:cx="75.655934"
|
||||||
|
inkscape:cy="-4"
|
||||||
|
inkscape:window-x="1097"
|
||||||
|
inkscape:window-y="185"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="Layer_1" /><g
|
||||||
|
id="g3"
|
||||||
|
transform="translate(-178,-172.8)"><path
|
||||||
|
d="m 306.8,213.8 0,-2.6 c 1.6,-0.1 2.9,-0.4 4.1,-0.8 1.2,-0.4 2.5,-1 4,-1.8 l 2.3,0 0,5.2 c 2.4,-1.9 4.2,-3.1 5.5,-3.8 2,-1 4,-1.5 5.8,-1.5 1.3,0 2.5,0.2 3.7,0.7 1.2,0.5 2.2,1 2.9,1.7 0.7,0.7 1.4,1.6 1.9,2.8 2.2,-1.9 4.2,-3.3 6,-4 1.9,-0.8 3.7,-1.2 5.6,-1.2 1.8,0 3.4,0.4 4.8,1.1 1.4,0.8 2.4,1.7 3,2.8 0.6,1.1 0.9,2.8 0.9,5 l 0,14.4 c 0,1.5 0,2.4 0.1,2.6 0.1,0.4 0.3,0.8 0.7,1.1 0.3,0.4 0.7,0.6 1.2,0.7 0.4,0.1 1.2,0.2 2.4,0.2 l 1,0 0,2.6 -15.5,0 0,-2.6 c 1.8,0 2.9,-0.1 3.5,-0.4 0.5,-0.2 0.9,-0.6 1.2,-1.2 0.3,-0.6 0.4,-1.6 0.4,-3.2 l 0,-13.7 c 0,-1.7 -0.2,-2.9 -0.5,-3.6 -0.3,-0.7 -0.9,-1.2 -1.7,-1.7 -0.8,-0.4 -1.8,-0.7 -3,-0.7 -1.5,0 -3,0.4 -4.6,1.2 -2.2,1.1 -3.9,2.3 -5.1,3.6 l 0,14.8 c 0,1.4 0.1,2.4 0.2,2.8 0.1,0.4 0.4,0.8 0.7,1.1 0.3,0.3 0.7,0.5 1.1,0.6 0.4,0.1 1.5,0.2 3.1,0.2 l 0,2.6 -15.3,0 0,-2.6 0.9,0 c 1.2,0 2.1,-0.1 2.6,-0.4 0.5,-0.3 0.9,-0.7 1.2,-1.3 0.2,-0.5 0.3,-1.5 0.3,-2.9 l 0,-13.2 c 0,-1.9 -0.2,-3.3 -0.5,-3.9 -0.3,-0.7 -0.9,-1.3 -1.7,-1.7 -0.8,-0.5 -1.8,-0.7 -3,-0.7 -1.3,0 -2.7,0.3 -4.1,1 -2,1 -3.9,2.2 -5.6,3.8 l 0,15.9 c 0,1 0.1,1.6 0.4,2.1 0.3,0.4 0.7,0.8 1.2,1.1 0.6,0.3 1.3,0.4 2.3,0.4 l 1.1,0 0,2.6 -15.6,0 0,-2.6 0.8,0 c 1.4,0 2.4,-0.1 2.8,-0.3 0.7,-0.3 1.1,-0.8 1.4,-1.5 0.2,-0.4 0.2,-1.3 0.2,-2.9 l 0,-18.1 -5.1,0 z"
|
||||||
|
id="path5"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
d="m 366.4,213.7 0,-2.6 c 1.7,-0.2 3.2,-0.5 4.3,-0.9 1.2,-0.4 2.5,-1 4,-1.7 l 2.3,0 0,24.9 c 0,0.9 0.1,1.5 0.4,2 0.2,0.4 0.6,0.8 1,0.9 0.4,0.2 1.3,0.3 2.4,0.3 l 1.5,0 0,2.6 -15.9,0 0,-2.6 1.3,0 c 1.4,0 2.3,-0.1 2.8,-0.4 0.5,-0.2 0.8,-0.6 1,-1.1 0.2,-0.5 0.3,-1.5 0.3,-3.2 l 0,-18.3 -5.4,0 z m 7.9,-19.2 c 1,0 1.8,0.3 2.5,1 0.7,0.7 1.1,1.5 1.1,2.5 0,1 -0.4,1.8 -1.1,2.5 -0.7,0.7 -1.6,1.1 -2.5,1.1 -1,0 -1.8,-0.4 -2.5,-1.1 -0.7,-0.7 -1.1,-1.6 -1.1,-2.5 0,-1 0.4,-1.8 1.1,-2.5 0.6,-0.6 1.5,-1 2.5,-1 z"
|
||||||
|
id="path7"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
d="m 413.1,230.6 2,1.6 c -3.9,5.2 -8.6,7.8 -14,7.8 -4.2,0 -7.8,-1.5 -10.7,-4.5 -2.9,-3 -4.4,-6.8 -4.4,-11.3 0,-3 0.7,-5.7 2,-8.1 1.3,-2.4 3.2,-4.2 5.6,-5.6 2.4,-1.3 5.2,-2 8.3,-2 3.6,0 6.5,0.9 8.9,2.6 2.4,1.7 3.6,3.5 3.6,5.3 0,1 -0.3,1.7 -0.8,2.2 -0.5,0.5 -1.2,0.8 -1.9,0.8 -0.4,0 -0.7,-0.1 -1.1,-0.3 -0.4,-0.2 -0.7,-0.5 -1.1,-0.9 -0.2,-0.2 -0.5,-0.8 -0.9,-1.7 -0.6,-1.2 -1,-2 -1.3,-2.4 -0.6,-0.8 -1.4,-1.5 -2.4,-2 -0.9,-0.5 -2,-0.7 -3.1,-0.7 -1.8,0 -3.4,0.5 -4.9,1.5 -1.5,1 -2.7,2.4 -3.6,4.3 -0.9,1.9 -1.3,4.2 -1.3,6.8 0,4.1 1.1,7.3 3.3,9.7 1.9,2.1 4.1,3.1 6.7,3.1 1.2,0 2.4,-0.2 3.6,-0.6 1.2,-0.4 2.4,-1 3.5,-1.8 0.9,-0.6 2.2,-1.8 4,-3.8 z"
|
||||||
|
id="path9"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
d="m 418.7,213.7 0,-2.6 c 1.5,-0.1 2.8,-0.4 4,-0.8 1.2,-0.4 2.5,-1 4,-1.9 l 2.3,0 0,5.9 c 1.5,-1.8 3.2,-3.2 5.1,-4.3 1.9,-1.1 3.7,-1.6 5.2,-1.6 1.5,0 2.7,0.4 3.6,1.1 0.9,0.7 1.3,1.6 1.3,2.6 0,0.7 -0.3,1.4 -0.9,2 -0.6,0.6 -1.3,0.9 -2.1,0.9 -0.4,0 -0.7,-0.1 -1,-0.2 -0.3,-0.1 -0.7,-0.3 -1.2,-0.7 -1.1,-0.7 -2.1,-1.1 -2.9,-1.1 -1,0 -2.2,0.4 -3.4,1.3 -1.6,1.1 -2.8,2.2 -3.7,3.3 l 0,14.4 c 0,1.2 0.1,2.1 0.2,2.5 0.1,0.4 0.4,0.8 0.7,1.1 0.3,0.3 0.7,0.6 1.1,0.7 0.5,0.1 1.3,0.2 2.4,0.2 l 1,0 0,2.6 -16,0 0,-2.6 1.3,0 c 1.3,0 2.1,-0.1 2.5,-0.3 0.5,-0.3 0.9,-0.7 1.2,-1.3 0.3,-0.5 0.4,-1.5 0.4,-3 l 0,-18.3 -5.1,0 z"
|
||||||
|
id="path11"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
d="m 462.8,208.5 c 3,0 5.7,0.6 7.9,1.9 2.2,1.3 4,3.1 5.3,5.5 1.3,2.4 1.9,5.2 1.9,8.3 0,3.1 -0.7,5.9 -2,8.3 -1.3,2.4 -3.1,4.3 -5.4,5.5 -2.3,1.3 -5,1.9 -8.1,1.9 -5,0 -8.8,-1.6 -11.3,-4.7 -2.5,-3.1 -3.8,-6.8 -3.8,-11 0,-3.1 0.7,-5.8 2,-8.2 1.3,-2.4 3.1,-4.2 5.5,-5.6 2.4,-1.2 5.1,-1.9 8,-1.9 z m -0.2,3 c -2.4,0 -4.4,0.9 -6,2.8 -2.1,2.3 -3.1,5.7 -3.1,10.1 0,4.3 0.9,7.5 2.6,9.7 1.6,2 3.8,3 6.5,3 1.8,0 3.3,-0.5 4.7,-1.4 1.4,-0.9 2.5,-2.4 3.3,-4.5 0.8,-2 1.3,-4.4 1.3,-7.2 0,-2.7 -0.5,-5.1 -1.4,-7.2 -0.7,-1.7 -1.8,-3 -3.2,-4 -1.3,-0.8 -2.9,-1.3 -4.7,-1.3 z"
|
||||||
|
id="path13"
|
||||||
|
inkscape:connector-curvature="0" /></g><path
|
||||||
|
d="M 51.6,0 C 23.1,0 0,23.1 0,51.6 c 0,28.5 23.1,51.6 51.6,51.6 28.5,0 51.6,-23.1 51.6,-51.6 C 103.2,23.1 80.1,0 51.6,0 Z m 24.5,58.6 c -0.5,2 -1.3,3.6 -2.4,4.9 -1,1.3 -2,2.1 -3.1,2.5 -1.1,0.4 -2.2,0.6 -3.4,0.6 -1.2,0 -2.2,-0.2 -3,-0.7 C 63.4,65.5 62.8,64.8 62.3,64 61.8,63.2 61.5,62.2 61.3,61.1 61.1,60 61,58.8 61,57.5 c 0,-0.5 0,-1 0.1,-1.7 0.1,-0.7 0.2,-1.6 0.3,-1.6 l -0.2,0 c -1.6,4 -3.8,6.9 -6.6,9.2 -2.8,2.3 -5.9,3.4 -9.3,3.4 -2.3,0 -4.2,-0.9 -5.5,-2.6 -1.4,-1.7 -2.1,-4.3 -2.1,-7.7 0,-0.5 0,-1 0.1,-1.6 0.1,-0.5 0.1,-0.7 0.2,-1.7 l -0.7,0 c -0.9,2 -1.7,4.8 -2.3,7.3 -0.6,2.5 -1.1,4.8 -1.4,6.9 -0.4,2.1 -0.6,4 -0.8,5.6 -0.2,1.6 -0.3,2.7 -0.4,3.3 0.1,0.5 0.2,1 0.3,1.6 0.2,0.6 0.3,1.2 0.5,1.7 0.2,0.5 0.3,1.1 0.4,1.6 0.1,0.5 0.2,0.9 0.2,1.2 0,1.4 -0.3,2.5 -0.9,3.2 -0.6,0.7 -1.3,1.1 -2,1.1 -0.9,0 -1.7,-0.3 -2.3,-0.8 -0.7,-0.6 -1,-1.5 -1,-2.7 0,-1.7 0.3,-3.9 0.9,-6.5 0.6,-2.6 1.5,-5.9 2.6,-9.8 0.6,-1.8 1.1,-3.6 1.7,-5.4 0.6,-1.8 1.1,-3.5 1.6,-5 0.5,-1.5 0.9,-2.9 1.3,-4.1 0.4,-1.2 0.6,-2.1 0.7,-2.8 0.1,-0.3 0.2,-1 0.3,-2 0.1,-1 0.2,-2.1 0.4,-3.4 0.2,-1.3 0.3,-2.7 0.5,-4.1 0.2,-1.5 0.4,-2.8 0.5,-4 0.2,-0.9 0.3,-1.9 0.5,-3 0.2,-1.1 0.5,-2.2 0.9,-3.1 0.4,-1 1,-1.8 1.7,-2.5 0.7,-0.7 1.6,-1 2.7,-1 1.2,0 2,0.4 2.4,1.1 0.4,0.7 0.6,1.6 0.5,2.6 -0.1,1 -0.2,2.1 -0.5,3.2 -0.3,1.1 -0.6,2.1 -0.9,2.9 -0.8,2.5 -1.6,4.8 -2.5,6.7 -0.9,1.9 -1.7,4 -2.4,6.2 -0.6,1.5 -0.8,2.9 -0.8,4.1 0,2.2 0.7,3.8 2,5 1.4,1.2 3,1.7 4.9,1.7 1.5,0 3,-0.5 4.4,-1.6 1.4,-1.1 2.7,-2.4 3.9,-3.9 1.2,-1.5 2.2,-3.1 3,-4.9 0.8,-1.7 1.4,-3.3 1.8,-4.6 0.1,-0.2 0.2,-0.6 0.3,-1.4 0.2,-0.8 0.3,-1.7 0.5,-2.7 0.2,-1 0.4,-2 0.6,-3.1 0.2,-1.1 0.4,-2 0.5,-2.7 0.2,-0.8 0.3,-1.6 0.5,-2.6 0.2,-1 0.5,-1.9 0.9,-2.8 0.4,-0.9 1,-1.6 1.6,-2.2 0.7,-0.6 1.5,-0.9 2.6,-0.9 1.3,0 2.1,0.4 2.6,1.1 0.4,0.7 0.6,1.6 0.6,2.6 -0.1,1 -0.2,2 -0.5,3 -0.3,1 -0.5,1.8 -0.7,2.4 -0.8,2.5 -1.6,4.7 -2.4,6.7 -0.8,2 -1.5,3.8 -2.2,5.2 -0.6,1.5 -1.1,2.6 -1.5,3.5 -0.4,0.9 -0.6,1.5 -0.6,1.8 0,2.6 0.6,4.5 1.7,5.6 1.1,1.1 2.3,1.7 3.6,1.7 2.2,0 3.9,-0.7 5.2,-2 1.3,-1.4 2.3,-3.9 2.9,-6.9 l 0.8,0 c 0.2,2.9 -0.1,5.3 -0.6,7.3 z"
|
||||||
|
id="path15"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#2e3192" /></svg>
|
||||||
|
After Width: | Height: | Size: 7.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 253 KiB |
@@ -1,11 +1,4 @@
|
|||||||
.\" micro manual page - micro(1)
|
.TH micro 1 "2020-02-10"
|
||||||
.\"
|
|
||||||
.\" Copyright © 2017 Zachary Yedidia <zyedidia@gmail.com>
|
|
||||||
.\" Copyright © 2017 Collin Warren <anatoly@somethinghub.com>
|
|
||||||
.\"
|
|
||||||
.\" This document is provided under the same licensing as micro.
|
|
||||||
.\" See \usr\share\doc\micro\LICENSE for more information.
|
|
||||||
.TH micro 1 "2017-03-28"
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
micro \- A modern and intuitive terminal-based text editor
|
micro \- A modern and intuitive terminal-based text editor
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@@ -22,39 +15,96 @@ As the name indicates, micro aims to be somewhat of a successor to the nano edit
|
|||||||
enjoyable to use full time, whether you work in the terminal because you prefer it (like me), or because you need to (over ssh).
|
enjoyable to use full time, whether you work in the terminal because you prefer it (like me), or because you need to (over ssh).
|
||||||
|
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
|
.PP
|
||||||
|
\-clean
|
||||||
|
.RS 4
|
||||||
|
Cleans the configuration directory
|
||||||
|
.RE
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
\-config-dir dir
|
\-config-dir dir
|
||||||
.RS 4
|
.RS 4
|
||||||
Specify a custom location for the configuration directory
|
Specify a custom location for the configuration directory
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
\-startpos LINE,COL
|
[FILE]:LINE:COL
|
||||||
.RS 4
|
.RS 4
|
||||||
Specify a line and column to start the cursor at when opening a buffer
|
Specify a line and column to start the cursor at when opening a buffer
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
\-options
|
\-options
|
||||||
.RS 4
|
.RS 4
|
||||||
Show all option help
|
Show all option help
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\-debug
|
||||||
|
.RS 4
|
||||||
|
Enable debug mode (enables logging to ./log.txt)
|
||||||
|
.RE
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
\-version
|
\-version
|
||||||
.RS 4
|
.RS 4
|
||||||
Show the version number and information
|
Show the version number and information
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
|
Micro's plugin's can be managed at the command line with the following commands.
|
||||||
|
.RS 4
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\-plugin remove [PLUGIN]...
|
||||||
|
.RS 4
|
||||||
|
Remove plugin(s)
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\-plugin update [PLUGIN]...
|
||||||
|
.RS 4
|
||||||
|
Update plugin(s) (if no argument is given, updates all plugins)
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\-plugin search [PLUGIN]...
|
||||||
|
.RS 4
|
||||||
|
Search for a plugin
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\-plugin list
|
||||||
|
.RS 4
|
||||||
|
List installed plugins
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\-plugin available
|
||||||
|
.RS 4
|
||||||
|
List available plugins
|
||||||
|
.RE
|
||||||
|
.RE
|
||||||
|
|
||||||
|
Micro's options can also be set via command line arguments for quick
|
||||||
|
adjustments. For real configuration, please use the settings.json
|
||||||
|
file (see 'help options').
|
||||||
|
.RS 4
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\-option value
|
||||||
|
.RS 4
|
||||||
|
Set `option` to `value` for this session
|
||||||
|
For example: `micro -syntax off file.c`
|
||||||
|
.RE
|
||||||
|
|
||||||
|
|
||||||
.SH CONFIGURATION
|
.SH CONFIGURATION
|
||||||
|
|
||||||
Micro uses
|
Micro uses $MICRO_CONFIG_HOME as the configuration directory.
|
||||||
\fI$XDG_CONFIG_HOME/micro\fR
|
If this environment variable is not set, it uses $XDG_CONFIG_HOME/micro instead.
|
||||||
for configuration by default. If it is not set, micro uses ~/.config/micro.
|
If that environment variable is not set, it uses ~/.config/micro as the configuration directory.
|
||||||
Two main configuration files are settings.json, containing the user's
|
In the documentation, we use ~/.config/micro to refer to the configuration directory
|
||||||
settings, and bindings.json, containing the user's custom keybindings.
|
(even if it may in fact be somewhere else if you have set either of the above environment variables).
|
||||||
|
|
||||||
.SH ENVIRONMENT
|
|
||||||
Micro's behaviour can be changed by setting environment variables, of which there is currently only one:
|
|
||||||
\fIMICRO_TRUECOLOR\fR.
|
|
||||||
When MICRO_TRUECOLOR is set to 1, micro will attempt to treat your terminal as a true-color terminal and will be able to make full use of the true-color colorschemes that are included with micro. If MICRO_TRUECOLOR is not set or is set to 0, then micro will only make use of 256 color features and will internally map true-color colorschemes to the nearest colors available. For more information see micro's documentation.
|
|
||||||
|
|
||||||
.SH NOTICE
|
.SH NOTICE
|
||||||
This manpage is intended only to serve as a quick guide to the invocation of
|
This manpage is intended only to serve as a quick guide to the invocation of
|
||||||
@@ -69,5 +119,5 @@ and to report any newly encountered bugs you may find. We strive to correct
|
|||||||
bugs as swiftly as possible.
|
bugs as swiftly as possible.
|
||||||
|
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright \(co 2017 Zachary Yedidia, Collin Warren, et al.
|
Copyright \(co 2020 Zachary Yedidia, et al.
|
||||||
See /usr/share/doc/micro/LICENSE and /usr/share/doc/micro/AUTHORS for more information.
|
See /usr/share/doc/micro/LICENSE and /usr/share/doc/micro/AUTHORS for more information.
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
isatty "github.com/mattn/go-isatty"
|
isatty "github.com/mattn/go-isatty"
|
||||||
|
lua "github.com/yuin/gopher-lua"
|
||||||
"github.com/zyedidia/micro/internal/action"
|
"github.com/zyedidia/micro/internal/action"
|
||||||
"github.com/zyedidia/micro/internal/buffer"
|
"github.com/zyedidia/micro/internal/buffer"
|
||||||
"github.com/zyedidia/micro/internal/config"
|
"github.com/zyedidia/micro/internal/config"
|
||||||
@@ -218,9 +219,6 @@ func main() {
|
|||||||
|
|
||||||
screen.Init()
|
screen.Init()
|
||||||
|
|
||||||
// If we have an error, we can exit cleanly and not completely
|
|
||||||
// mess up the terminal being worked in
|
|
||||||
// In other words we need to shut down tcell before the program crashes
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
screen.Screen.Fini()
|
screen.Screen.Fini()
|
||||||
@@ -280,52 +278,68 @@ func main() {
|
|||||||
|
|
||||||
// clear the drawchan so we don't redraw excessively
|
// clear the drawchan so we don't redraw excessively
|
||||||
// if someone requested a redraw before we started displaying
|
// if someone requested a redraw before we started displaying
|
||||||
for len(screen.DrawChan) > 0 {
|
for len(screen.DrawChan()) > 0 {
|
||||||
<-screen.DrawChan
|
<-screen.DrawChan()
|
||||||
}
|
}
|
||||||
|
|
||||||
var event tcell.Event
|
|
||||||
|
|
||||||
// wait for initial resize event
|
// wait for initial resize event
|
||||||
select {
|
select {
|
||||||
case event = <-events:
|
case event := <-events:
|
||||||
action.Tabs.HandleEvent(event)
|
action.Tabs.HandleEvent(event)
|
||||||
case <-time.After(10 * time.Millisecond):
|
case <-time.After(10 * time.Millisecond):
|
||||||
// time out after 10ms
|
// time out after 10ms
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Since this loop is very slow (waits for user input every time) it's
|
||||||
|
// okay to be inefficient and run it via a function every time
|
||||||
|
// We do this so we can recover from panics without crashing the editor
|
||||||
for {
|
for {
|
||||||
// Display everything
|
DoEvent()
|
||||||
screen.Screen.Fill(' ', config.DefStyle)
|
}
|
||||||
screen.Screen.HideCursor()
|
}
|
||||||
action.Tabs.Display()
|
|
||||||
for _, ep := range action.MainTab().Panes {
|
// DoEvent runs the main action loop of the editor
|
||||||
ep.Display()
|
func DoEvent() {
|
||||||
}
|
var event tcell.Event
|
||||||
action.MainTab().Display()
|
|
||||||
action.InfoBar.Display()
|
// recover from errors without crashing the editor
|
||||||
screen.Screen.Show()
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
event = nil
|
if e, ok := err.(*lua.ApiError); ok {
|
||||||
|
screen.TermMessage("Lua API error:", e)
|
||||||
// Check for new events
|
} else {
|
||||||
select {
|
screen.TermMessage("Micro encountered an error:", errors.Wrap(err, 2).ErrorStack(), "\nIf you can reproduce this error, please report it at https://github.com/zyedidia/micro/issues")
|
||||||
case f := <-shell.Jobs:
|
}
|
||||||
// If a new job has finished while running in the background we should execute the callback
|
}
|
||||||
f.Function(f.Output, f.Args)
|
}()
|
||||||
case <-config.Autosave:
|
// Display everything
|
||||||
for _, b := range buffer.OpenBuffers {
|
screen.Screen.Fill(' ', config.DefStyle)
|
||||||
b.Save()
|
screen.Screen.HideCursor()
|
||||||
}
|
action.Tabs.Display()
|
||||||
case <-shell.CloseTerms:
|
for _, ep := range action.MainTab().Panes {
|
||||||
case event = <-events:
|
ep.Display()
|
||||||
case <-screen.DrawChan:
|
}
|
||||||
}
|
action.MainTab().Display()
|
||||||
|
action.InfoBar.Display()
|
||||||
if action.InfoBar.HasPrompt {
|
screen.Screen.Show()
|
||||||
action.InfoBar.HandleEvent(event)
|
|
||||||
} else {
|
// Check for new events
|
||||||
action.Tabs.HandleEvent(event)
|
select {
|
||||||
}
|
case f := <-shell.Jobs:
|
||||||
|
// If a new job has finished while running in the background we should execute the callback
|
||||||
|
f.Function(f.Output, f.Args)
|
||||||
|
case <-config.Autosave:
|
||||||
|
for _, b := range buffer.OpenBuffers {
|
||||||
|
b.Save()
|
||||||
|
}
|
||||||
|
case <-shell.CloseTerms:
|
||||||
|
case event = <-events:
|
||||||
|
case <-screen.DrawChan():
|
||||||
|
}
|
||||||
|
|
||||||
|
if action.InfoBar.HasPrompt {
|
||||||
|
action.InfoBar.HandleEvent(event)
|
||||||
|
} else {
|
||||||
|
action.Tabs.HandleEvent(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -8,6 +8,7 @@ require (
|
|||||||
github.com/mattn/go-isatty v0.0.11
|
github.com/mattn/go-isatty v0.0.11
|
||||||
github.com/mattn/go-runewidth v0.0.7
|
github.com/mattn/go-runewidth v0.0.7
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
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/sergi/go-diff v1.1.0
|
||||||
github.com/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.4.0
|
||||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb
|
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb
|
||||||
@@ -16,9 +17,10 @@ require (
|
|||||||
github.com/zyedidia/highlight v0.0.0-20170330143449-201131ce5cf5
|
github.com/zyedidia/highlight v0.0.0-20170330143449-201131ce5cf5
|
||||||
github.com/zyedidia/json5 v0.0.0-20200102012142-2da050b1a98d
|
github.com/zyedidia/json5 v0.0.0-20200102012142-2da050b1a98d
|
||||||
github.com/zyedidia/pty v2.0.0+incompatible // indirect
|
github.com/zyedidia/pty v2.0.0+incompatible // indirect
|
||||||
github.com/zyedidia/tcell v1.4.2
|
github.com/zyedidia/tcell v1.4.4
|
||||||
github.com/zyedidia/terminal v0.0.0-20180726154117-533c623e2415
|
github.com/zyedidia/terminal v0.0.0-20180726154117-533c623e2415
|
||||||
golang.org/x/text v0.3.2
|
golang.org/x/text v0.3.2
|
||||||
|
gopkg.in/sourcemap.v1 v1.0.5 // indirect
|
||||||
gopkg.in/yaml.v2 v2.2.7
|
gopkg.in/yaml.v2 v2.2.7
|
||||||
layeh.com/gopher-luar v1.0.7
|
layeh.com/gopher-luar v1.0.7
|
||||||
)
|
)
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -29,6 +29,8 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
|
|||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||||
@@ -50,8 +52,8 @@ github.com/zyedidia/poller v1.0.1 h1:Tt9S3AxAjXwWGNiC2TUdRJkQDZSzCBNVQ4xXiQ7440s
|
|||||||
github.com/zyedidia/poller v1.0.1/go.mod h1:vZXJOHGDcuK08GXhF6IAY0ZFd2WcgOR5DOTp84Uk5eE=
|
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 h1:Ou5vXL6tvjst+RV8sUFISbuKDnUJPhnpygApMFGweqw=
|
||||||
github.com/zyedidia/pty v2.0.0+incompatible/go.mod h1:4y9l9yJZNxRa7GB/fB+mmDmGkG3CqmzLf4vUxGGotEA=
|
github.com/zyedidia/pty v2.0.0+incompatible/go.mod h1:4y9l9yJZNxRa7GB/fB+mmDmGkG3CqmzLf4vUxGGotEA=
|
||||||
github.com/zyedidia/tcell v1.4.2 h1:JWMDs6O1saINPIR5M3kNqlWJwkfnBZeZDZszEJi3BW8=
|
github.com/zyedidia/tcell v1.4.4 h1:o34LXujNuSueuyTy+5eoQW+rQr8g0UbY8k1NczZyskQ=
|
||||||
github.com/zyedidia/tcell v1.4.2/go.mod h1:HhlbMSCcGX15rFDB+Q1Lk3pKEOocsCUAQC3zhZ9sadA=
|
github.com/zyedidia/tcell v1.4.4/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 h1:752dTQ5OatJ9M5ULK2+9lor+nzyZz+LYDo3WGngg3Rc=
|
||||||
github.com/zyedidia/terminal v0.0.0-20180726154117-533c623e2415/go.mod h1:8leT8G0Cm8NoJHdrrKHyR9MirWoF4YW7pZh06B6H+1E=
|
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=
|
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -65,6 +67,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
|||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
|
||||||
|
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ func (h *BufPane) SelectWordLeft() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartOfLine moves the cursor to the start of the text of the line
|
// StartOfText moves the cursor to the start of the text of the line
|
||||||
func (h *BufPane) StartOfText() bool {
|
func (h *BufPane) StartOfText() bool {
|
||||||
h.Cursor.Deselect(true)
|
h.Cursor.Deselect(true)
|
||||||
h.Cursor.StartOfText()
|
h.Cursor.StartOfText()
|
||||||
@@ -396,6 +396,7 @@ func (h *BufPane) CursorStart() bool {
|
|||||||
h.Cursor.Deselect(true)
|
h.Cursor.Deselect(true)
|
||||||
h.Cursor.X = 0
|
h.Cursor.X = 0
|
||||||
h.Cursor.Y = 0
|
h.Cursor.Y = 0
|
||||||
|
h.Cursor.StoreVisualX()
|
||||||
h.Relocate()
|
h.Relocate()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -566,6 +567,20 @@ func (h *BufPane) IndentSelection() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IndentLine moves the current line forward one indentation
|
||||||
|
func (h *BufPane) IndentLine() bool {
|
||||||
|
if h.Cursor.HasSelection() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
tabsize := int(h.Buf.Settings["tabsize"].(float64))
|
||||||
|
indentstr := h.Buf.IndentString(tabsize)
|
||||||
|
h.Buf.Insert(buffer.Loc{X: 0, Y: h.Cursor.Y}, indentstr)
|
||||||
|
h.Buf.RelocateCursors()
|
||||||
|
h.Relocate()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// OutdentLine moves the current line back one indentation
|
// OutdentLine moves the current line back one indentation
|
||||||
func (h *BufPane) OutdentLine() bool {
|
func (h *BufPane) OutdentLine() bool {
|
||||||
if h.Cursor.HasSelection() {
|
if h.Cursor.HasSelection() {
|
||||||
@@ -620,6 +635,11 @@ func (h *BufPane) Autocomplete() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !util.IsNonAlphaNumeric(h.Cursor.RuneUnder(h.Cursor.X)) {
|
||||||
|
// don't autocomplete if cursor is on alpha numeric character (middle of a word)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if b.HasSuggestions {
|
if b.HasSuggestions {
|
||||||
b.CycleAutocomplete(true)
|
b.CycleAutocomplete(true)
|
||||||
return true
|
return true
|
||||||
@@ -659,23 +679,27 @@ func (h *BufPane) SaveAll() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the buffer to disk
|
// SaveCB performs a save and does a callback at the very end (after all prompts have been resolved)
|
||||||
func (h *BufPane) Save() bool {
|
func (h *BufPane) SaveCB(action string, callback func()) bool {
|
||||||
// If this is an empty buffer, ask for a filename
|
// If this is an empty buffer, ask for a filename
|
||||||
if h.Buf.Path == "" {
|
if h.Buf.Path == "" {
|
||||||
h.SaveAs()
|
h.SaveAsCB(action, callback)
|
||||||
} else {
|
} else {
|
||||||
noPrompt := h.saveBufToFile(h.Buf.Path, "Save")
|
noPrompt := h.saveBufToFile(h.Buf.Path, action, callback)
|
||||||
if noPrompt {
|
if noPrompt {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveAs saves the buffer to disk with the given name
|
// Save the buffer to disk
|
||||||
func (h *BufPane) SaveAs() bool {
|
func (h *BufPane) Save() bool {
|
||||||
|
return h.SaveCB("Save", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveAsCB performs a save as and does a callback at the very end (after all prompts have been resolved)
|
||||||
|
func (h *BufPane) SaveAsCB(action string, callback func()) bool {
|
||||||
InfoBar.Prompt("Filename: ", "", "Save", nil, func(resp string, canceled bool) {
|
InfoBar.Prompt("Filename: ", "", "Save", nil, func(resp string, canceled bool) {
|
||||||
if !canceled {
|
if !canceled {
|
||||||
// the filename might or might not be quoted, so unquote first then join the strings.
|
// the filename might or might not be quoted, so unquote first then join the strings.
|
||||||
@@ -689,35 +713,50 @@ func (h *BufPane) SaveAs() bool {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
filename := strings.Join(args, " ")
|
filename := strings.Join(args, " ")
|
||||||
noPrompt := h.saveBufToFile(filename, "SaveAs")
|
noPrompt := h.saveBufToFile(filename, action, callback)
|
||||||
if noPrompt {
|
if noPrompt {
|
||||||
h.completeAction("SaveAs")
|
h.completeAction(action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SaveAs saves the buffer to disk with the given name
|
||||||
|
func (h *BufPane) SaveAs() bool {
|
||||||
|
return h.SaveAsCB("SaveAs", nil)
|
||||||
|
}
|
||||||
|
|
||||||
// This function saves the buffer to `filename` and changes the buffer's path and name
|
// This function saves the buffer to `filename` and changes the buffer's path and name
|
||||||
// to `filename` if the save is successful
|
// to `filename` if the save is successful
|
||||||
func (h *BufPane) saveBufToFile(filename string, action string) bool {
|
func (h *BufPane) saveBufToFile(filename string, action string, callback func()) bool {
|
||||||
err := h.Buf.SaveAs(filename)
|
err := h.Buf.SaveAs(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.HasSuffix(err.Error(), "permission denied") {
|
if strings.HasSuffix(err.Error(), "permission denied") {
|
||||||
InfoBar.YNPrompt("Permission denied. Do you want to save this file using sudo? (y,n)", func(yes, canceled bool) {
|
saveWithSudo := func() {
|
||||||
if yes && !canceled {
|
err = h.Buf.SaveAsWithSudo(filename)
|
||||||
err = h.Buf.SaveAsWithSudo(filename)
|
if err != nil {
|
||||||
if err != nil {
|
InfoBar.Error(err)
|
||||||
InfoBar.Error(err)
|
} else {
|
||||||
} else {
|
h.Buf.Path = filename
|
||||||
h.Buf.Path = filename
|
h.Buf.SetName(filename)
|
||||||
h.Buf.SetName(filename)
|
InfoBar.Message("Saved " + filename)
|
||||||
InfoBar.Message("Saved " + filename)
|
|
||||||
}
|
|
||||||
h.completeAction(action)
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
return false
|
if h.Buf.Settings["autosu"].(bool) {
|
||||||
|
saveWithSudo()
|
||||||
|
} else {
|
||||||
|
InfoBar.YNPrompt("Permission denied. Do you want to save this file using sudo? (y,n)", func(yes, canceled bool) {
|
||||||
|
if yes && !canceled {
|
||||||
|
saveWithSudo()
|
||||||
|
h.completeAction(action)
|
||||||
|
}
|
||||||
|
if callback != nil {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
InfoBar.Error(err)
|
InfoBar.Error(err)
|
||||||
}
|
}
|
||||||
@@ -726,6 +765,9 @@ func (h *BufPane) saveBufToFile(filename string, action string) bool {
|
|||||||
h.Buf.SetName(filename)
|
h.Buf.SetName(filename)
|
||||||
InfoBar.Message("Saved " + filename)
|
InfoBar.Message("Saved " + filename)
|
||||||
}
|
}
|
||||||
|
if callback != nil {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1040,11 +1082,15 @@ func (h *BufPane) JumpToMatchingBrace() bool {
|
|||||||
r := h.Cursor.RuneUnder(h.Cursor.X)
|
r := h.Cursor.RuneUnder(h.Cursor.X)
|
||||||
rl := h.Cursor.RuneUnder(h.Cursor.X - 1)
|
rl := h.Cursor.RuneUnder(h.Cursor.X - 1)
|
||||||
if r == bp[0] || r == bp[1] || rl == bp[0] || rl == bp[1] {
|
if r == bp[0] || r == bp[1] || rl == bp[0] || rl == bp[1] {
|
||||||
matchingBrace, left := h.Buf.FindMatchingBrace(bp, h.Cursor.Loc)
|
matchingBrace, left, found := h.Buf.FindMatchingBrace(bp, h.Cursor.Loc)
|
||||||
if left {
|
if found {
|
||||||
h.Cursor.GotoLoc(matchingBrace)
|
if left {
|
||||||
|
h.Cursor.GotoLoc(matchingBrace)
|
||||||
|
} else {
|
||||||
|
h.Cursor.GotoLoc(matchingBrace.Move(1, h.Buf))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
h.Cursor.GotoLoc(matchingBrace.Move(1, h.Buf))
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1195,6 +1241,21 @@ func (h *BufPane) HalfPageDown() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToggleDiffGutter turns the diff gutter off and on
|
||||||
|
func (h *BufPane) ToggleDiffGutter() bool {
|
||||||
|
if !h.Buf.Settings["diffgutter"].(bool) {
|
||||||
|
h.Buf.Settings["diffgutter"] = true
|
||||||
|
h.Buf.UpdateDiff(func(synchronous bool) {
|
||||||
|
screen.Redraw()
|
||||||
|
})
|
||||||
|
InfoBar.Message("Enabled diff gutter")
|
||||||
|
} else {
|
||||||
|
h.Buf.Settings["diffgutter"] = false
|
||||||
|
InfoBar.Message("Disabled diff gutter")
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// ToggleRuler turns line numbers off and on
|
// ToggleRuler turns line numbers off and on
|
||||||
func (h *BufPane) ToggleRuler() bool {
|
func (h *BufPane) ToggleRuler() bool {
|
||||||
if !h.Buf.Settings["ruler"].(bool) {
|
if !h.Buf.Settings["ruler"].(bool) {
|
||||||
@@ -1280,15 +1341,17 @@ func (h *BufPane) Quit() bool {
|
|||||||
if h.Buf.Modified() {
|
if h.Buf.Modified() {
|
||||||
if config.GlobalSettings["autosave"].(float64) > 0 {
|
if config.GlobalSettings["autosave"].(float64) > 0 {
|
||||||
// autosave on means we automatically save when quitting
|
// autosave on means we automatically save when quitting
|
||||||
h.Save()
|
h.SaveCB("Quit", func() {
|
||||||
quit()
|
quit()
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
InfoBar.YNPrompt("Save changes to "+h.Buf.GetName()+" before closing? (y,n,esc)", func(yes, canceled bool) {
|
InfoBar.YNPrompt("Save changes to "+h.Buf.GetName()+" before closing? (y,n,esc)", func(yes, canceled bool) {
|
||||||
if !canceled && !yes {
|
if !canceled && !yes {
|
||||||
quit()
|
quit()
|
||||||
} else if !canceled && yes {
|
} else if !canceled && yes {
|
||||||
h.Save()
|
h.SaveCB("Quit", func() {
|
||||||
quit()
|
quit()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1505,7 +1568,7 @@ func (h *BufPane) SpawnMultiCursorUp() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SpawnMultiCursorUp creates additional cursor, at the same X (if possible), one Y more.
|
// SpawnMultiCursorDown creates additional cursor, at the same X (if possible), one Y more.
|
||||||
func (h *BufPane) SpawnMultiCursorDown() bool {
|
func (h *BufPane) SpawnMultiCursorDown() bool {
|
||||||
if h.Cursor.Y+1 == h.Buf.LinesNum() {
|
if h.Cursor.Y+1 == h.Buf.LinesNum() {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
@@ -14,13 +15,22 @@ import (
|
|||||||
"github.com/zyedidia/tcell"
|
"github.com/zyedidia/tcell"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func createBindingsIfNotExist(fname string) {
|
||||||
|
if _, e := os.Stat(fname); os.IsNotExist(e) {
|
||||||
|
ioutil.WriteFile(fname, []byte("{}"), 0644)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitBindings intializes the bindings map by reading from bindings.json
|
||||||
func InitBindings() {
|
func InitBindings() {
|
||||||
config.Bindings = DefaultBindings()
|
config.Bindings = DefaultBindings()
|
||||||
|
|
||||||
var parsed map[string]string
|
var parsed map[string]string
|
||||||
defaults := DefaultBindings()
|
defaults := DefaultBindings()
|
||||||
|
|
||||||
filename := config.ConfigDir + "/bindings.json"
|
filename := filepath.Join(config.ConfigDir, "bindings.json")
|
||||||
|
createBindingsIfNotExist(filename)
|
||||||
|
|
||||||
if _, e := os.Stat(filename); e == nil {
|
if _, e := os.Stat(filename); e == nil {
|
||||||
input, err := ioutil.ReadFile(filename)
|
input, err := ioutil.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -158,7 +168,8 @@ func TryBindKey(k, v string, overwrite bool) (bool, error) {
|
|||||||
var e error
|
var e error
|
||||||
var parsed map[string]string
|
var parsed map[string]string
|
||||||
|
|
||||||
filename := config.ConfigDir + "/bindings.json"
|
filename := filepath.Join(config.ConfigDir, "bindings.json")
|
||||||
|
createBindingsIfNotExist(filename)
|
||||||
if _, e = os.Stat(filename); e == nil {
|
if _, e = os.Stat(filename); e == nil {
|
||||||
input, err := ioutil.ReadFile(filename)
|
input, err := ioutil.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -207,7 +218,8 @@ func UnbindKey(k string) error {
|
|||||||
var e error
|
var e error
|
||||||
var parsed map[string]string
|
var parsed map[string]string
|
||||||
|
|
||||||
filename := config.ConfigDir + "/bindings.json"
|
filename := filepath.Join(config.ConfigDir, "bindings.json")
|
||||||
|
createBindingsIfNotExist(filename)
|
||||||
if _, e = os.Stat(filename); e == nil {
|
if _, e = os.Stat(filename); e == nil {
|
||||||
input, err := ioutil.ReadFile(filename)
|
input, err := ioutil.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -113,6 +113,9 @@ func BufMapKey(k Event, action string) {
|
|||||||
success := true
|
success := true
|
||||||
for i, a := range actionfns {
|
for i, a := range actionfns {
|
||||||
for j, c := range cursors {
|
for j, c := range cursors {
|
||||||
|
if c == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
h.Buf.SetCurCursor(c.Num)
|
h.Buf.SetCurCursor(c.Num)
|
||||||
h.Cursor = c
|
h.Cursor = c
|
||||||
if i == 0 || (success && types[i-1] == '&') || (!success && types[i-1] == '|') || (types[i-1] == ',') {
|
if i == 0 || (success && types[i-1] == '&') || (!success && types[i-1] == '|') || (types[i-1] == ',') {
|
||||||
@@ -267,13 +270,20 @@ func (h *BufPane) SetID(i uint64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *BufPane) Name() string {
|
func (h *BufPane) Name() string {
|
||||||
return h.Buf.GetName()
|
n := h.Buf.GetName()
|
||||||
|
if h.Buf.Modified() {
|
||||||
|
n += " +"
|
||||||
|
}
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleEvent executes the tcell event properly
|
// HandleEvent executes the tcell event properly
|
||||||
func (h *BufPane) HandleEvent(event tcell.Event) {
|
func (h *BufPane) HandleEvent(event tcell.Event) {
|
||||||
if h.Buf.ExternallyModified() {
|
if h.Buf.ExternallyModified() && !h.Buf.ReloadDisabled {
|
||||||
InfoBar.YNPrompt("The file on disk has changed. Reload file? (y,n)", func(yes, canceled bool) {
|
InfoBar.YNPrompt("The file on disk has changed. Reload file? (y,n,esc)", func(yes, canceled bool) {
|
||||||
|
if canceled {
|
||||||
|
h.Buf.DisableReload()
|
||||||
|
}
|
||||||
if !yes || canceled {
|
if !yes || canceled {
|
||||||
h.Buf.UpdateModTime()
|
h.Buf.UpdateModTime()
|
||||||
} else {
|
} else {
|
||||||
@@ -452,6 +462,7 @@ func (h *BufPane) DoRuneInsert(r rune) {
|
|||||||
if recording_macro {
|
if recording_macro {
|
||||||
curmacro = append(curmacro, r)
|
curmacro = append(curmacro, r)
|
||||||
}
|
}
|
||||||
|
h.Relocate()
|
||||||
h.PluginCBRune("onRune", r)
|
h.PluginCBRune("onRune", r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -556,6 +567,7 @@ var BufKeyActions = map[string]BufKeyAction{
|
|||||||
"Autocomplete": (*BufPane).Autocomplete,
|
"Autocomplete": (*BufPane).Autocomplete,
|
||||||
"CycleAutocompleteBack": (*BufPane).CycleAutocompleteBack,
|
"CycleAutocompleteBack": (*BufPane).CycleAutocompleteBack,
|
||||||
"OutdentLine": (*BufPane).OutdentLine,
|
"OutdentLine": (*BufPane).OutdentLine,
|
||||||
|
"IndentLine": (*BufPane).IndentLine,
|
||||||
"Paste": (*BufPane).Paste,
|
"Paste": (*BufPane).Paste,
|
||||||
"PastePrimary": (*BufPane).PastePrimary,
|
"PastePrimary": (*BufPane).PastePrimary,
|
||||||
"SelectAll": (*BufPane).SelectAll,
|
"SelectAll": (*BufPane).SelectAll,
|
||||||
@@ -573,6 +585,7 @@ var BufKeyActions = map[string]BufKeyAction{
|
|||||||
"EndOfLine": (*BufPane).EndOfLine,
|
"EndOfLine": (*BufPane).EndOfLine,
|
||||||
"ToggleHelp": (*BufPane).ToggleHelp,
|
"ToggleHelp": (*BufPane).ToggleHelp,
|
||||||
"ToggleKeyMenu": (*BufPane).ToggleKeyMenu,
|
"ToggleKeyMenu": (*BufPane).ToggleKeyMenu,
|
||||||
|
"ToggleDiffGutter": (*BufPane).ToggleDiffGutter,
|
||||||
"ToggleRuler": (*BufPane).ToggleRuler,
|
"ToggleRuler": (*BufPane).ToggleRuler,
|
||||||
"ClearStatus": (*BufPane).ClearStatus,
|
"ClearStatus": (*BufPane).ClearStatus,
|
||||||
"ShellMode": (*BufPane).ShellMode,
|
"ShellMode": (*BufPane).ShellMode,
|
||||||
@@ -660,6 +673,7 @@ var MultiActions = map[string]bool{
|
|||||||
"IndentSelection": true,
|
"IndentSelection": true,
|
||||||
"OutdentSelection": true,
|
"OutdentSelection": true,
|
||||||
"OutdentLine": true,
|
"OutdentLine": true,
|
||||||
|
"IndentLine": true,
|
||||||
"Paste": true,
|
"Paste": true,
|
||||||
"PastePrimary": true,
|
"PastePrimary": true,
|
||||||
"SelectPageUp": true,
|
"SelectPageUp": true,
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ func (h *BufPane) PluginCmd(args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if h.Buf.Type != buffer.BTLog {
|
if h.Buf.Type != buffer.BTLog {
|
||||||
OpenLogBuf(h)
|
h.OpenLogBuf()
|
||||||
}
|
}
|
||||||
|
|
||||||
config.PluginCommand(buffer.LogBuf, args[0], args[1:])
|
config.PluginCommand(buffer.LogBuf, args[0], args[1:])
|
||||||
@@ -272,7 +272,7 @@ func (h *BufPane) OpenCmd(args []string) {
|
|||||||
// ToggleLogCmd toggles the log view
|
// ToggleLogCmd toggles the log view
|
||||||
func (h *BufPane) ToggleLogCmd(args []string) {
|
func (h *BufPane) ToggleLogCmd(args []string) {
|
||||||
if h.Buf.Type != buffer.BTLog {
|
if h.Buf.Type != buffer.BTLog {
|
||||||
OpenLogBuf(h)
|
h.OpenLogBuf()
|
||||||
} else {
|
} else {
|
||||||
h.Quit()
|
h.Quit()
|
||||||
}
|
}
|
||||||
@@ -475,7 +475,7 @@ func SetGlobalOptionNative(option string, nativeValue interface{}) error {
|
|||||||
b.SetOptionNative(option, nativeValue)
|
b.SetOptionNative(option, nativeValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
return config.WriteSettings(config.ConfigDir + "/settings.json")
|
return config.WriteSettings(filepath.Join(config.ConfigDir, "settings.json"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetGlobalOption(option, value string) error {
|
func SetGlobalOption(option, value string) error {
|
||||||
@@ -732,23 +732,22 @@ func (h *BufPane) ReplaceCmd(args []string) {
|
|||||||
|
|
||||||
nreplaced := 0
|
nreplaced := 0
|
||||||
start := h.Buf.Start()
|
start := h.Buf.Start()
|
||||||
// end := h.Buf.End()
|
end := h.Buf.End()
|
||||||
// if h.Cursor.HasSelection() {
|
if h.Cursor.HasSelection() {
|
||||||
// start = h.Cursor.CurSelection[0]
|
start = h.Cursor.CurSelection[0]
|
||||||
// end = h.Cursor.CurSelection[1]
|
end = h.Cursor.CurSelection[1]
|
||||||
// }
|
}
|
||||||
if all {
|
if all {
|
||||||
nreplaced = h.Buf.ReplaceRegex(start, h.Buf.End(), regex, replace)
|
nreplaced, _ = h.Buf.ReplaceRegex(start, end, regex, replace)
|
||||||
} else {
|
} else {
|
||||||
inRange := func(l buffer.Loc) bool {
|
inRange := func(l buffer.Loc) bool {
|
||||||
return l.GreaterEqual(start) && l.LessEqual(h.Buf.End())
|
return l.GreaterEqual(start) && l.LessEqual(end)
|
||||||
}
|
}
|
||||||
|
|
||||||
searchLoc := start
|
searchLoc := start
|
||||||
searching := true
|
|
||||||
var doReplacement func()
|
var doReplacement func()
|
||||||
doReplacement = func() {
|
doReplacement = func() {
|
||||||
locs, found, err := h.Buf.FindNext(search, start, h.Buf.End(), searchLoc, true, !noRegex)
|
locs, found, err := h.Buf.FindNext(search, start, end, searchLoc, true, !noRegex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InfoBar.Error(err)
|
InfoBar.Error(err)
|
||||||
return
|
return
|
||||||
@@ -764,10 +763,11 @@ func (h *BufPane) ReplaceCmd(args []string) {
|
|||||||
|
|
||||||
InfoBar.YNPrompt("Perform replacement (y,n,esc)", func(yes, canceled bool) {
|
InfoBar.YNPrompt("Perform replacement (y,n,esc)", func(yes, canceled bool) {
|
||||||
if !canceled && yes {
|
if !canceled && yes {
|
||||||
h.Buf.Replace(locs[0], locs[1], replaceStr)
|
_, nrunes := h.Buf.ReplaceRegex(locs[0], locs[1], regex, replace)
|
||||||
|
|
||||||
searchLoc = locs[0]
|
searchLoc = locs[0]
|
||||||
searchLoc.X += utf8.RuneCount(replace)
|
searchLoc.X += nrunes + locs[0].Diff(locs[1], h.Buf)
|
||||||
|
end.Move(nrunes, h.Buf)
|
||||||
h.Cursor.Loc = searchLoc
|
h.Cursor.Loc = searchLoc
|
||||||
nreplaced++
|
nreplaced++
|
||||||
} else if !canceled && !yes {
|
} else if !canceled && !yes {
|
||||||
@@ -778,9 +778,7 @@ func (h *BufPane) ReplaceCmd(args []string) {
|
|||||||
h.Buf.RelocateCursors()
|
h.Buf.RelocateCursors()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if searching {
|
doReplacement()
|
||||||
doReplacement()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
doReplacement()
|
doReplacement()
|
||||||
@@ -807,6 +805,11 @@ func (h *BufPane) ReplaceAllCmd(args []string) {
|
|||||||
func (h *BufPane) TermCmd(args []string) {
|
func (h *BufPane) TermCmd(args []string) {
|
||||||
ps := h.tab.Panes
|
ps := h.tab.Panes
|
||||||
|
|
||||||
|
if !TermEmuSupported {
|
||||||
|
InfoBar.Error("Terminal emulator not supported on this system")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
sh := os.Getenv("SHELL")
|
sh := os.Getenv("SHELL")
|
||||||
if sh == "" {
|
if sh == "" {
|
||||||
@@ -830,7 +833,12 @@ func (h *BufPane) TermCmd(args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
v := h.GetView()
|
v := h.GetView()
|
||||||
MainTab().Panes[i] = NewTermPane(v.X, v.Y, v.Width, v.Height, t, id, MainTab())
|
tp, err := NewTermPane(v.X, v.Y, v.Width, v.Height, t, id, MainTab())
|
||||||
|
if err != nil {
|
||||||
|
InfoBar.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
MainTab().Panes[i] = tp
|
||||||
MainTab().SetActive(i)
|
MainTab().SetActive(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,15 +5,18 @@ import "github.com/zyedidia/micro/internal/buffer"
|
|||||||
var InfoBar *InfoPane
|
var InfoBar *InfoPane
|
||||||
var LogBufPane *BufPane
|
var LogBufPane *BufPane
|
||||||
|
|
||||||
|
// InitGlobals initializes the log buffer and the info bar
|
||||||
func InitGlobals() {
|
func InitGlobals() {
|
||||||
InfoBar = NewInfoBar()
|
InfoBar = NewInfoBar()
|
||||||
buffer.LogBuf = buffer.NewBufferFromString("", "Log", buffer.BTLog)
|
buffer.LogBuf = buffer.NewBufferFromString("", "Log", buffer.BTLog)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetInfoBar returns the infobar pane
|
||||||
func GetInfoBar() *InfoPane {
|
func GetInfoBar() *InfoPane {
|
||||||
return InfoBar
|
return InfoBar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WriteLog writes a string to the log buffer
|
||||||
func WriteLog(s string) {
|
func WriteLog(s string) {
|
||||||
buffer.WriteLog(s)
|
buffer.WriteLog(s)
|
||||||
if LogBufPane != nil {
|
if LogBufPane != nil {
|
||||||
@@ -28,7 +31,10 @@ func WriteLog(s string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func OpenLogBuf(h *BufPane) {
|
// OpenLogBuf opens the log buffer from the current bufpane
|
||||||
|
// If the current bufpane is a log buffer nothing happens,
|
||||||
|
// otherwise the log buffer is opened in a horizontal split
|
||||||
|
func (h *BufPane) OpenLogBuf() {
|
||||||
LogBufPane = h.HSplitBuf(buffer.LogBuf)
|
LogBufPane = h.HSplitBuf(buffer.LogBuf)
|
||||||
LogBufPane.CursorEnd()
|
LogBufPane.CursorEnd()
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/zyedidia/micro/internal/buffer"
|
||||||
"github.com/zyedidia/micro/internal/display"
|
"github.com/zyedidia/micro/internal/display"
|
||||||
"github.com/zyedidia/micro/internal/info"
|
"github.com/zyedidia/micro/internal/info"
|
||||||
"github.com/zyedidia/micro/internal/util"
|
"github.com/zyedidia/micro/internal/util"
|
||||||
@@ -68,7 +69,7 @@ func (h *InfoPane) HandleEvent(event tcell.Event) {
|
|||||||
h.EventCallback(resp)
|
h.EventCallback(resp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *tcell.EventMouse:
|
default:
|
||||||
h.BufPane.HandleEvent(event)
|
h.BufPane.HandleEvent(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,6 +124,7 @@ var InfoNones = []string{
|
|||||||
"HalfPageDown",
|
"HalfPageDown",
|
||||||
"ToggleHelp",
|
"ToggleHelp",
|
||||||
"ToggleKeyMenu",
|
"ToggleKeyMenu",
|
||||||
|
"ToggleDiffGutter",
|
||||||
"ToggleRuler",
|
"ToggleRuler",
|
||||||
"JumpLine",
|
"JumpLine",
|
||||||
"ClearStatus",
|
"ClearStatus",
|
||||||
@@ -185,14 +187,17 @@ func (h *InfoPane) Autocomplete() {
|
|||||||
args := bytes.Split(l, []byte{' '})
|
args := bytes.Split(l, []byte{' '})
|
||||||
cmd := string(args[0])
|
cmd := string(args[0])
|
||||||
|
|
||||||
if len(args) == 1 {
|
if h.PromptType == "Command" {
|
||||||
b.Autocomplete(CommandComplete)
|
if len(args) == 1 {
|
||||||
} else {
|
b.Autocomplete(CommandComplete)
|
||||||
if action, ok := commands[cmd]; ok {
|
} else if action, ok := commands[cmd]; ok {
|
||||||
if action.completer != nil {
|
if action.completer != nil {
|
||||||
b.Autocomplete(action.completer)
|
b.Autocomplete(action.completer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// by default use filename autocompletion
|
||||||
|
b.Autocomplete(buffer.FileComplete)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,13 @@ func (t *TabList) HandleEvent(event tcell.Event) {
|
|||||||
mx, my := e.Position()
|
mx, my := e.Position()
|
||||||
switch e.Buttons() {
|
switch e.Buttons() {
|
||||||
case tcell.Button1:
|
case tcell.Button1:
|
||||||
|
if my == t.Y && mx == 0 {
|
||||||
|
t.Scroll(-4)
|
||||||
|
return
|
||||||
|
} else if my == t.Y && mx == t.Width-1 {
|
||||||
|
t.Scroll(4)
|
||||||
|
return
|
||||||
|
}
|
||||||
if len(t.List) > 1 {
|
if len(t.List) > 1 {
|
||||||
ind := t.LocFromVisual(buffer.Loc{mx, my})
|
ind := t.LocFromVisual(buffer.Loc{mx, my})
|
||||||
if ind != -1 {
|
if ind != -1 {
|
||||||
|
|||||||
@@ -30,7 +30,12 @@ func RunTermEmulator(h *BufPane, input string, wait bool, getOutput bool, callba
|
|||||||
id := MainTab().Panes[0].ID()
|
id := MainTab().Panes[0].ID()
|
||||||
|
|
||||||
v := h.GetView()
|
v := h.GetView()
|
||||||
MainTab().Panes[0] = NewTermPane(v.X, v.Y, v.Width, v.Height, t, id, MainTab())
|
|
||||||
|
tp, err := NewTermPane(v.X, v.Y, v.Width, v.Height, t, id, MainTab())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
MainTab().Panes[0] = tp
|
||||||
MainTab().SetActive(0)
|
MainTab().SetActive(0)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package action
|
package action
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/zyedidia/clipboard"
|
"github.com/zyedidia/clipboard"
|
||||||
@@ -20,14 +21,18 @@ type TermPane struct {
|
|||||||
tab *Tab
|
tab *Tab
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTermPane(x, y, w, h int, t *shell.Terminal, id uint64, tab *Tab) *TermPane {
|
func NewTermPane(x, y, w, h int, t *shell.Terminal, id uint64, tab *Tab) (*TermPane, error) {
|
||||||
|
if !TermEmuSupported {
|
||||||
|
return nil, errors.New("Terminal emulator is not supported on this system")
|
||||||
|
}
|
||||||
|
|
||||||
th := new(TermPane)
|
th := new(TermPane)
|
||||||
th.Terminal = t
|
th.Terminal = t
|
||||||
th.id = id
|
th.id = id
|
||||||
th.mouseReleased = true
|
th.mouseReleased = true
|
||||||
th.Window = display.NewTermWindow(x, y, w, h, t)
|
th.Window = display.NewTermWindow(x, y, w, h, t)
|
||||||
th.tab = tab
|
th.tab = tab
|
||||||
return th
|
return th, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TermPane) ID() uint64 {
|
func (t *TermPane) ID() uint64 {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/zyedidia/micro/internal/config"
|
"github.com/zyedidia/micro/internal/config"
|
||||||
@@ -42,12 +43,12 @@ func (b *Buffer) Backup(checkTime bool) error {
|
|||||||
|
|
||||||
b.lastbackup = time.Now()
|
b.lastbackup = time.Now()
|
||||||
|
|
||||||
backupdir := config.ConfigDir + "/backups/"
|
backupdir := filepath.Join(config.ConfigDir, "backups")
|
||||||
if _, err := os.Stat(backupdir); os.IsNotExist(err) {
|
if _, err := os.Stat(backupdir); os.IsNotExist(err) {
|
||||||
os.Mkdir(backupdir, os.ModePerm)
|
os.Mkdir(backupdir, os.ModePerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
name := backupdir + util.EscapePath(b.AbsPath)
|
name := filepath.Join(backupdir, util.EscapePath(b.AbsPath))
|
||||||
|
|
||||||
err := overwriteFile(name, encoding.Nop, func(file io.Writer) (e error) {
|
err := overwriteFile(name, encoding.Nop, func(file io.Writer) (e error) {
|
||||||
if len(b.lines) == 0 {
|
if len(b.lines) == 0 {
|
||||||
@@ -81,7 +82,7 @@ func (b *Buffer) RemoveBackup() {
|
|||||||
if !b.Settings["backup"].(bool) || b.Path == "" || b.Type != BTDefault {
|
if !b.Settings["backup"].(bool) || b.Path == "" || b.Type != BTDefault {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f := config.ConfigDir + "/backups/" + util.EscapePath(b.AbsPath)
|
f := filepath.Join(config.ConfigDir, "backups", util.EscapePath(b.AbsPath))
|
||||||
os.Remove(f)
|
os.Remove(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +90,7 @@ func (b *Buffer) RemoveBackup() {
|
|||||||
// Returns true if a backup was applied
|
// Returns true if a backup was applied
|
||||||
func (b *Buffer) ApplyBackup(fsize int64) bool {
|
func (b *Buffer) ApplyBackup(fsize int64) bool {
|
||||||
if b.Settings["backup"].(bool) && len(b.Path) > 0 && b.Type == BTDefault {
|
if b.Settings["backup"].(bool) && len(b.Path) > 0 && b.Type == BTDefault {
|
||||||
backupfile := config.ConfigDir + "/backups/" + util.EscapePath(b.AbsPath)
|
backupfile := filepath.Join(config.ConfigDir, "backups", util.EscapePath(b.AbsPath))
|
||||||
if info, err := os.Stat(backupfile); err == nil {
|
if info, err := os.Stat(backupfile); err == nil {
|
||||||
backup, err := os.Open(backupfile)
|
backup, err := os.Open(backupfile)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package buffer
|
package buffer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -17,6 +18,7 @@ import (
|
|||||||
|
|
||||||
luar "layeh.com/gopher-luar"
|
luar "layeh.com/gopher-luar"
|
||||||
|
|
||||||
|
dmp "github.com/sergi/go-diff/diffmatchpatch"
|
||||||
"github.com/zyedidia/micro/internal/config"
|
"github.com/zyedidia/micro/internal/config"
|
||||||
ulua "github.com/zyedidia/micro/internal/lua"
|
ulua "github.com/zyedidia/micro/internal/lua"
|
||||||
"github.com/zyedidia/micro/internal/screen"
|
"github.com/zyedidia/micro/internal/screen"
|
||||||
@@ -73,13 +75,51 @@ type SharedBuffer struct {
|
|||||||
// Type of the buffer (e.g. help, raw, scratch etc..)
|
// Type of the buffer (e.g. help, raw, scratch etc..)
|
||||||
Type BufType
|
Type BufType
|
||||||
|
|
||||||
|
// Path to the file on disk
|
||||||
|
Path string
|
||||||
|
// Absolute path to the file on disk
|
||||||
|
AbsPath string
|
||||||
|
// Name of the buffer on the status line
|
||||||
|
name string
|
||||||
|
|
||||||
|
// Settings customized by the user
|
||||||
|
Settings map[string]interface{}
|
||||||
|
|
||||||
|
Suggestions []string
|
||||||
|
Completions []string
|
||||||
|
CurSuggestion int
|
||||||
|
|
||||||
|
Messages []*Message
|
||||||
|
|
||||||
|
updateDiffTimer *time.Timer
|
||||||
|
diffBase []byte
|
||||||
|
diffBaseLineCount int
|
||||||
|
diffLock sync.RWMutex
|
||||||
|
diff map[int]DiffStatus
|
||||||
|
|
||||||
|
// counts the number of edits
|
||||||
|
// resets every backupTime edits
|
||||||
|
lastbackup time.Time
|
||||||
|
|
||||||
|
// ReloadDisabled allows the user to disable reloads if they
|
||||||
|
// are viewing a file that is constantly changing
|
||||||
|
ReloadDisabled bool
|
||||||
|
|
||||||
isModified bool
|
isModified bool
|
||||||
// Whether or not suggestions can be autocompleted must be shared because
|
// Whether or not suggestions can be autocompleted must be shared because
|
||||||
// it changes based on how the buffer has changed
|
// it changes based on how the buffer has changed
|
||||||
HasSuggestions bool
|
HasSuggestions bool
|
||||||
|
|
||||||
// Modifications is the list of modified regions for syntax highlighting
|
// The Highlighter struct actually performs the highlighting
|
||||||
Modifications []Loc
|
Highlighter *highlight.Highlighter
|
||||||
|
// SyntaxDef represents the syntax highlighting definition being used
|
||||||
|
// This stores the highlighting rules and filetype detection info
|
||||||
|
SyntaxDef *highlight.Def
|
||||||
|
|
||||||
|
ModifiedThisFrame bool
|
||||||
|
|
||||||
|
// Hash of the original buffer -- empty if fastdirty is on
|
||||||
|
origHash [md5.Size]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *SharedBuffer) insert(pos Loc, value []byte) {
|
func (b *SharedBuffer) insert(pos Loc, value []byte) {
|
||||||
@@ -87,17 +127,49 @@ func (b *SharedBuffer) insert(pos Loc, value []byte) {
|
|||||||
b.HasSuggestions = false
|
b.HasSuggestions = false
|
||||||
b.LineArray.insert(pos, value)
|
b.LineArray.insert(pos, value)
|
||||||
|
|
||||||
// b.Modifications is cleared every screen redraw so it's
|
inslines := bytes.Count(value, []byte{'\n'})
|
||||||
// ok to append duplicates
|
b.MarkModified(pos.Y, pos.Y+inslines)
|
||||||
b.Modifications = append(b.Modifications, Loc{pos.Y, pos.Y + bytes.Count(value, []byte{'\n'})})
|
|
||||||
}
|
}
|
||||||
func (b *SharedBuffer) remove(start, end Loc) []byte {
|
func (b *SharedBuffer) remove(start, end Loc) []byte {
|
||||||
b.isModified = true
|
b.isModified = true
|
||||||
b.HasSuggestions = false
|
b.HasSuggestions = false
|
||||||
b.Modifications = append(b.Modifications, Loc{start.Y, start.Y})
|
defer b.MarkModified(start.Y, end.Y)
|
||||||
return b.LineArray.remove(start, end)
|
return b.LineArray.remove(start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkModified marks the buffer as modified for this frame
|
||||||
|
// and performs rehighlighting if syntax highlighting is enabled
|
||||||
|
func (b *SharedBuffer) MarkModified(start, end int) {
|
||||||
|
b.ModifiedThisFrame = true
|
||||||
|
|
||||||
|
if !b.Settings["syntax"].(bool) || b.SyntaxDef == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
start = util.Clamp(start, 0, len(b.lines))
|
||||||
|
end = util.Clamp(end, 0, len(b.lines))
|
||||||
|
|
||||||
|
l := -1
|
||||||
|
for i := start; i <= end; i++ {
|
||||||
|
l = util.Max(b.Highlighter.ReHighlightStates(b, i), l)
|
||||||
|
}
|
||||||
|
b.Highlighter.HighlightMatches(b, start, l+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableReload disables future reloads of this sharedbuffer
|
||||||
|
func (b *SharedBuffer) DisableReload() {
|
||||||
|
b.ReloadDisabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
DSUnchanged = 0
|
||||||
|
DSAdded = 1
|
||||||
|
DSModified = 2
|
||||||
|
DSDeletedAbove = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
type DiffStatus byte
|
||||||
|
|
||||||
// Buffer stores the main information about a currently open file including
|
// Buffer stores the main information about a currently open file including
|
||||||
// the actual text (in a LineArray), the undo/redo stack (in an EventHandler)
|
// the actual text (in a LineArray), the undo/redo stack (in an EventHandler)
|
||||||
// all the cursors, the syntax highlighting info, the settings for the buffer
|
// all the cursors, the syntax highlighting info, the settings for the buffer
|
||||||
@@ -112,36 +184,6 @@ type Buffer struct {
|
|||||||
cursors []*Cursor
|
cursors []*Cursor
|
||||||
curCursor int
|
curCursor int
|
||||||
StartCursor Loc
|
StartCursor Loc
|
||||||
|
|
||||||
// Path to the file on disk
|
|
||||||
Path string
|
|
||||||
// Absolute path to the file on disk
|
|
||||||
AbsPath string
|
|
||||||
// Name of the buffer on the status line
|
|
||||||
name string
|
|
||||||
|
|
||||||
// SyntaxDef represents the syntax highlighting definition being used
|
|
||||||
// This stores the highlighting rules and filetype detection info
|
|
||||||
SyntaxDef *highlight.Def
|
|
||||||
// The Highlighter struct actually performs the highlighting
|
|
||||||
Highlighter *highlight.Highlighter
|
|
||||||
HighlightLock sync.Mutex
|
|
||||||
|
|
||||||
// Hash of the original buffer -- empty if fastdirty is on
|
|
||||||
origHash [md5.Size]byte
|
|
||||||
|
|
||||||
// Settings customized by the user
|
|
||||||
Settings map[string]interface{}
|
|
||||||
|
|
||||||
Suggestions []string
|
|
||||||
Completions []string
|
|
||||||
CurSuggestion int
|
|
||||||
|
|
||||||
Messages []*Message
|
|
||||||
|
|
||||||
// counts the number of edits
|
|
||||||
// resets every backupTime edits
|
|
||||||
lastbackup time.Time
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBufferFromFile opens a new buffer using the given path
|
// NewBufferFromFile opens a new buffer using the given path
|
||||||
@@ -196,22 +238,6 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT
|
|||||||
|
|
||||||
b := new(Buffer)
|
b := new(Buffer)
|
||||||
|
|
||||||
b.Settings = config.DefaultCommonSettings()
|
|
||||||
for k, v := range config.GlobalSettings {
|
|
||||||
if _, ok := b.Settings[k]; ok {
|
|
||||||
b.Settings[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
config.InitLocalSettings(b.Settings, path)
|
|
||||||
|
|
||||||
enc, err := htmlindex.Get(b.Settings["encoding"].(string))
|
|
||||||
if err != nil {
|
|
||||||
enc = unicode.UTF8
|
|
||||||
b.Settings["encoding"] = "utf-8"
|
|
||||||
}
|
|
||||||
|
|
||||||
reader := transform.NewReader(r, enc.NewDecoder())
|
|
||||||
|
|
||||||
found := false
|
found := false
|
||||||
if len(path) > 0 {
|
if len(path) > 0 {
|
||||||
for _, buf := range OpenBuffers {
|
for _, buf := range OpenBuffers {
|
||||||
@@ -223,28 +249,44 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b.Path = path
|
|
||||||
b.AbsPath = absPath
|
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
b.SharedBuffer = new(SharedBuffer)
|
b.SharedBuffer = new(SharedBuffer)
|
||||||
b.Type = btype
|
b.Type = btype
|
||||||
|
|
||||||
|
b.AbsPath = absPath
|
||||||
|
b.Path = path
|
||||||
|
|
||||||
|
b.Settings = config.DefaultCommonSettings()
|
||||||
|
for k, v := range config.GlobalSettings {
|
||||||
|
if _, ok := config.DefaultGlobalOnlySettings[k]; !ok {
|
||||||
|
// make sure setting is not global-only
|
||||||
|
b.Settings[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.InitLocalSettings(b.Settings, path)
|
||||||
|
|
||||||
|
enc, err := htmlindex.Get(b.Settings["encoding"].(string))
|
||||||
|
if err != nil {
|
||||||
|
enc = unicode.UTF8
|
||||||
|
b.Settings["encoding"] = "utf-8"
|
||||||
|
}
|
||||||
|
|
||||||
hasBackup := b.ApplyBackup(size)
|
hasBackup := b.ApplyBackup(size)
|
||||||
|
|
||||||
if !hasBackup {
|
if !hasBackup {
|
||||||
|
reader := bufio.NewReader(transform.NewReader(r, enc.NewDecoder()))
|
||||||
b.LineArray = NewLineArray(uint64(size), FFAuto, reader)
|
b.LineArray = NewLineArray(uint64(size), FFAuto, reader)
|
||||||
}
|
}
|
||||||
b.EventHandler = NewEventHandler(b.SharedBuffer, b.cursors)
|
b.EventHandler = NewEventHandler(b.SharedBuffer, b.cursors)
|
||||||
|
|
||||||
|
// The last time this file was modified
|
||||||
|
b.UpdateModTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.Settings["readonly"].(bool) && b.Type == BTDefault {
|
if b.Settings["readonly"].(bool) && b.Type == BTDefault {
|
||||||
b.Type.Readonly = true
|
b.Type.Readonly = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// The last time this file was modified
|
|
||||||
b.UpdateModTime()
|
|
||||||
|
|
||||||
switch b.Endings {
|
switch b.Endings {
|
||||||
case FFUnix:
|
case FFUnix:
|
||||||
b.Settings["fileformat"] = "unix"
|
b.Settings["fileformat"] = "unix"
|
||||||
@@ -253,10 +295,11 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT
|
|||||||
}
|
}
|
||||||
|
|
||||||
b.UpdateRules()
|
b.UpdateRules()
|
||||||
|
// init local settings again now that we know the filetype
|
||||||
config.InitLocalSettings(b.Settings, b.Path)
|
config.InitLocalSettings(b.Settings, b.Path)
|
||||||
|
|
||||||
if _, err := os.Stat(config.ConfigDir + "/buffers/"); os.IsNotExist(err) {
|
if _, err := os.Stat(filepath.Join(config.ConfigDir, "buffers")); os.IsNotExist(err) {
|
||||||
os.Mkdir(config.ConfigDir+"/buffers/", os.ModePerm)
|
os.Mkdir(filepath.Join(config.ConfigDir, "buffers"), os.ModePerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
if startcursor.X != -1 && startcursor.Y != -1 {
|
if startcursor.X != -1 && startcursor.Y != -1 {
|
||||||
@@ -273,7 +316,7 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT
|
|||||||
b.AddCursor(NewCursor(b, b.StartCursor))
|
b.AddCursor(NewCursor(b, b.StartCursor))
|
||||||
b.GetActiveCursor().Relocate()
|
b.GetActiveCursor().Relocate()
|
||||||
|
|
||||||
if !b.Settings["fastdirty"].(bool) {
|
if !b.Settings["fastdirty"].(bool) && !found {
|
||||||
if size > LargeFileThreshold {
|
if size > LargeFileThreshold {
|
||||||
// If the file is larger than LargeFileThreshold fastdirty needs to be on
|
// If the file is larger than LargeFileThreshold fastdirty needs to be on
|
||||||
b.Settings["fastdirty"] = true
|
b.Settings["fastdirty"] = true
|
||||||
@@ -282,13 +325,11 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = config.RunPluginFn("onBufferOpen", luar.New(ulua.L, b))
|
err := config.RunPluginFn("onBufferOpen", luar.New(ulua.L, b))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
screen.TermMessage(err)
|
screen.TermMessage(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.Modifications = make([]Loc, 0, 10)
|
|
||||||
|
|
||||||
OpenBuffers = append(OpenBuffers, b)
|
OpenBuffers = append(OpenBuffers, b)
|
||||||
|
|
||||||
return b
|
return b
|
||||||
@@ -319,13 +360,17 @@ func (b *Buffer) Fini() {
|
|||||||
// GetName returns the name that should be displayed in the statusline
|
// GetName returns the name that should be displayed in the statusline
|
||||||
// for this buffer
|
// for this buffer
|
||||||
func (b *Buffer) GetName() string {
|
func (b *Buffer) GetName() string {
|
||||||
if b.name == "" {
|
name := b.name
|
||||||
|
if name == "" {
|
||||||
if b.Path == "" {
|
if b.Path == "" {
|
||||||
return "No name"
|
return "No name"
|
||||||
}
|
}
|
||||||
return b.Path
|
name = b.Path
|
||||||
}
|
}
|
||||||
return b.name
|
if b.Settings["basename"].(bool) {
|
||||||
|
return path.Base(name)
|
||||||
|
}
|
||||||
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetName changes the name for this buffer
|
//SetName changes the name for this buffer
|
||||||
@@ -355,16 +400,6 @@ func (b *Buffer) Remove(start, end Loc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearModifications clears the list of modified lines in this buffer
|
|
||||||
// The list of modified lines is used for syntax highlighting so that
|
|
||||||
// we can selectively highlight only the necessary lines
|
|
||||||
// This function should be called every time this buffer is drawn to
|
|
||||||
// the screen
|
|
||||||
func (b *Buffer) ClearModifications() {
|
|
||||||
// clear slice without resetting the cap
|
|
||||||
b.Modifications = b.Modifications[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// FileType returns the buffer's filetype
|
// FileType returns the buffer's filetype
|
||||||
func (b *Buffer) FileType() string {
|
func (b *Buffer) FileType() string {
|
||||||
return b.Settings["filetype"].(string)
|
return b.Settings["filetype"].(string)
|
||||||
@@ -398,7 +433,7 @@ func (b *Buffer) ReOpen() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
reader := transform.NewReader(file, enc.NewDecoder())
|
reader := bufio.NewReader(transform.NewReader(file, enc.NewDecoder()))
|
||||||
data, err := ioutil.ReadAll(reader)
|
data, err := ioutil.ReadAll(reader)
|
||||||
txt := string(data)
|
txt := string(data)
|
||||||
|
|
||||||
@@ -408,6 +443,9 @@ func (b *Buffer) ReOpen() error {
|
|||||||
b.EventHandler.ApplyDiff(txt)
|
b.EventHandler.ApplyDiff(txt)
|
||||||
|
|
||||||
err = b.UpdateModTime()
|
err = b.UpdateModTime()
|
||||||
|
if !b.Settings["fastdirty"].(bool) {
|
||||||
|
calcHash(b, &b.origHash)
|
||||||
|
}
|
||||||
b.isModified = false
|
b.isModified = false
|
||||||
b.RelocateCursors()
|
b.RelocateCursors()
|
||||||
return err
|
return err
|
||||||
@@ -528,7 +566,6 @@ func (b *Buffer) UpdateRules() {
|
|||||||
if syntaxFile == "" {
|
if syntaxFile == "" {
|
||||||
// search for the syntax file in the user's custom syntax files
|
// search for the syntax file in the user's custom syntax files
|
||||||
for _, f := range config.ListRealRuntimeFiles(config.RTSyntax) {
|
for _, f := range config.ListRealRuntimeFiles(config.RTSyntax) {
|
||||||
log.Println("real runtime file", f.Name())
|
|
||||||
data, err := f.Data()
|
data, err := f.Data()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
screen.TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
|
screen.TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
|
||||||
@@ -627,7 +664,7 @@ func (b *Buffer) UpdateRules() {
|
|||||||
go func() {
|
go func() {
|
||||||
b.Highlighter.HighlightStates(b)
|
b.Highlighter.HighlightStates(b)
|
||||||
b.Highlighter.HighlightMatches(b, 0, b.End().Y)
|
b.Highlighter.HighlightMatches(b, 0, b.End().Y)
|
||||||
screen.DrawChan <- true
|
screen.Redraw()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -804,7 +841,7 @@ var BracePairs = [][2]rune{
|
|||||||
// returns the location of the matching brace
|
// returns the location of the matching brace
|
||||||
// if the boolean returned is true then the original matching brace is one character left
|
// if the boolean returned is true then the original matching brace is one character left
|
||||||
// of the starting location
|
// of the starting location
|
||||||
func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) (Loc, bool) {
|
func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) (Loc, bool, bool) {
|
||||||
curLine := []rune(string(b.LineBytes(start.Y)))
|
curLine := []rune(string(b.LineBytes(start.Y)))
|
||||||
startChar := ' '
|
startChar := ' '
|
||||||
if start.X >= 0 && start.X < len(curLine) {
|
if start.X >= 0 && start.X < len(curLine) {
|
||||||
@@ -834,9 +871,9 @@ func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) (Loc, bool) {
|
|||||||
i--
|
i--
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
if startChar == braceType[0] {
|
if startChar == braceType[0] {
|
||||||
return Loc{x, y}, false
|
return Loc{x, y}, false, true
|
||||||
}
|
}
|
||||||
return Loc{x, y}, true
|
return Loc{x, y}, true, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -858,9 +895,9 @@ func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) (Loc, bool) {
|
|||||||
i--
|
i--
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
if leftChar == braceType[1] {
|
if leftChar == braceType[1] {
|
||||||
return Loc{x, y}, true
|
return Loc{x, y}, true, true
|
||||||
}
|
}
|
||||||
return Loc{x, y}, false
|
return Loc{x, y}, false, true
|
||||||
}
|
}
|
||||||
} else if r == braceType[1] {
|
} else if r == braceType[1] {
|
||||||
i++
|
i++
|
||||||
@@ -868,7 +905,7 @@ func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) (Loc, bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return start, true
|
return start, true, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retab changes all tabs to spaces or vice versa
|
// Retab changes all tabs to spaces or vice versa
|
||||||
@@ -891,6 +928,7 @@ func (b *Buffer) Retab() {
|
|||||||
|
|
||||||
l = bytes.TrimLeft(l, " \t")
|
l = bytes.TrimLeft(l, " \t")
|
||||||
b.lines[i].data = append(ws, l...)
|
b.lines[i].data = append(ws, l...)
|
||||||
|
b.MarkModified(i, i)
|
||||||
dirty = true
|
dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -932,6 +970,101 @@ func (b *Buffer) Write(bytes []byte) (n int, err error) {
|
|||||||
return len(bytes), nil
|
return len(bytes), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Buffer) updateDiffSync() {
|
||||||
|
b.diffLock.Lock()
|
||||||
|
defer b.diffLock.Unlock()
|
||||||
|
|
||||||
|
b.diff = make(map[int]DiffStatus)
|
||||||
|
|
||||||
|
if b.diffBase == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
differ := dmp.New()
|
||||||
|
baseRunes, bufferRunes, _ := differ.DiffLinesToRunes(string(b.diffBase), string(b.Bytes()))
|
||||||
|
diffs := differ.DiffMainRunes(baseRunes, bufferRunes, false)
|
||||||
|
lineN := 0
|
||||||
|
|
||||||
|
for _, diff := range diffs {
|
||||||
|
lineCount := len([]rune(diff.Text))
|
||||||
|
|
||||||
|
switch diff.Type {
|
||||||
|
case dmp.DiffEqual:
|
||||||
|
lineN += lineCount
|
||||||
|
case dmp.DiffInsert:
|
||||||
|
var status DiffStatus
|
||||||
|
if b.diff[lineN] == DSDeletedAbove {
|
||||||
|
status = DSModified
|
||||||
|
} else {
|
||||||
|
status = DSAdded
|
||||||
|
}
|
||||||
|
for i := 0; i < lineCount; i++ {
|
||||||
|
b.diff[lineN] = status
|
||||||
|
lineN++
|
||||||
|
}
|
||||||
|
case dmp.DiffDelete:
|
||||||
|
b.diff[lineN] = DSDeletedAbove
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateDiff computes the diff between the diff base and the buffer content.
|
||||||
|
// The update may be performed synchronously or asynchronously.
|
||||||
|
// UpdateDiff calls the supplied callback when the update is complete.
|
||||||
|
// The argument passed to the callback is set to true if and only if
|
||||||
|
// the update was performed synchronously.
|
||||||
|
// If an asynchronous update is already pending when UpdateDiff is called,
|
||||||
|
// UpdateDiff does not schedule another update, in which case the callback
|
||||||
|
// is not called.
|
||||||
|
func (b *Buffer) UpdateDiff(callback func(bool)) {
|
||||||
|
if b.updateDiffTimer != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lineCount := b.LinesNum()
|
||||||
|
if b.diffBaseLineCount > lineCount {
|
||||||
|
lineCount = b.diffBaseLineCount
|
||||||
|
}
|
||||||
|
|
||||||
|
if lineCount < 1000 {
|
||||||
|
b.updateDiffSync()
|
||||||
|
callback(true)
|
||||||
|
} else if lineCount < 30000 {
|
||||||
|
b.updateDiffTimer = time.AfterFunc(500*time.Millisecond, func() {
|
||||||
|
b.updateDiffTimer = nil
|
||||||
|
b.updateDiffSync()
|
||||||
|
callback(false)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// Don't compute diffs for very large files
|
||||||
|
b.diffLock.Lock()
|
||||||
|
b.diff = make(map[int]DiffStatus)
|
||||||
|
b.diffLock.Unlock()
|
||||||
|
callback(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDiffBase sets the text that is used as the base for diffing the buffer content
|
||||||
|
func (b *Buffer) SetDiffBase(diffBase []byte) {
|
||||||
|
b.diffBase = diffBase
|
||||||
|
if diffBase == nil {
|
||||||
|
b.diffBaseLineCount = 0
|
||||||
|
} else {
|
||||||
|
b.diffBaseLineCount = strings.Count(string(diffBase), "\n")
|
||||||
|
}
|
||||||
|
b.UpdateDiff(func(synchronous bool) {
|
||||||
|
screen.Redraw()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiffStatus returns the diff status for a line in the buffer
|
||||||
|
func (b *Buffer) DiffStatus(lineN int) DiffStatus {
|
||||||
|
b.diffLock.RLock()
|
||||||
|
defer b.diffLock.RUnlock()
|
||||||
|
// Note that the zero value for DiffStatus is equal to DSUnchanged
|
||||||
|
return b.diff[lineN]
|
||||||
|
}
|
||||||
|
|
||||||
// WriteLog writes a string to the log buffer
|
// WriteLog writes a string to the log buffer
|
||||||
func WriteLog(s string) {
|
func WriteLog(s string) {
|
||||||
LogBuf.EventHandler.Insert(LogBuf.End(), s)
|
LogBuf.EventHandler.Insert(LogBuf.End(), s)
|
||||||
|
|||||||
1889
internal/buffer/buffer_generated_test.go
Normal file
1889
internal/buffer/buffer_generated_test.go
Normal file
File diff suppressed because it is too large
Load Diff
111
internal/buffer/buffer_test.go
Normal file
111
internal/buffer/buffer_test.go
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package buffer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
testifyAssert "github.com/stretchr/testify/assert"
|
||||||
|
lua "github.com/yuin/gopher-lua"
|
||||||
|
|
||||||
|
ulua "github.com/zyedidia/micro/internal/lua"
|
||||||
|
)
|
||||||
|
|
||||||
|
type operation struct {
|
||||||
|
start Loc
|
||||||
|
end Loc
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := NewBufferFromString(strings.Join(before, "\n"), "", BTDefault)
|
||||||
|
|
||||||
|
assert.NotEqual("", b.GetName())
|
||||||
|
assert.Equal(false, b.ExternallyModified())
|
||||||
|
assert.Equal(false, b.Modified())
|
||||||
|
assert.Equal(1, b.NumCursors())
|
||||||
|
|
||||||
|
checkText := func(lines []string) {
|
||||||
|
assert.Equal([]byte(strings.Join(lines, "\n")), b.Bytes())
|
||||||
|
assert.Equal(len(lines), b.LinesNum())
|
||||||
|
for i, s := range lines {
|
||||||
|
assert.Equal(s, b.Line(i))
|
||||||
|
assert.Equal([]byte(s), b.LineBytes(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkText(before)
|
||||||
|
|
||||||
|
var cursors []*Cursor
|
||||||
|
|
||||||
|
for _, op := range operations {
|
||||||
|
cursor := NewCursor(b, op.start)
|
||||||
|
cursor.SetSelectionStart(op.start)
|
||||||
|
cursor.SetSelectionEnd(op.end)
|
||||||
|
b.AddCursor(cursor)
|
||||||
|
cursors = append(cursors, cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(1+len(operations), b.NumCursors())
|
||||||
|
|
||||||
|
for i, op := range operations {
|
||||||
|
cursor := cursors[i]
|
||||||
|
b.SetCurCursor(cursor.Num)
|
||||||
|
cursor.DeleteSelection()
|
||||||
|
cursor.ResetSelection()
|
||||||
|
b.Insert(cursor.Loc, strings.Join(op.text, "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
checkText(after)
|
||||||
|
|
||||||
|
for b.UndoStack.Peek() != nil {
|
||||||
|
b.UndoOneEvent()
|
||||||
|
}
|
||||||
|
|
||||||
|
checkText(before)
|
||||||
|
|
||||||
|
for i, op := range operations {
|
||||||
|
cursor := cursors[i]
|
||||||
|
if !cursor.HasSelection() {
|
||||||
|
assert.Equal(op.start, cursor.Loc)
|
||||||
|
} else {
|
||||||
|
assert.Equal(op.start, cursor.CurSelection[0])
|
||||||
|
assert.Equal(op.end, cursor.CurSelection[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for b.RedoStack.Peek() != nil {
|
||||||
|
b.RedoOneEvent()
|
||||||
|
}
|
||||||
|
|
||||||
|
checkText(after)
|
||||||
|
|
||||||
|
b.Close()
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ package buffer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"log"
|
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
@@ -42,6 +41,73 @@ type Delta struct {
|
|||||||
End Loc
|
End Loc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DoTextEvent runs a text event
|
||||||
|
func (eh *EventHandler) DoTextEvent(t *TextEvent, useUndo bool) {
|
||||||
|
oldl := eh.buf.LinesNum()
|
||||||
|
|
||||||
|
if useUndo {
|
||||||
|
eh.Execute(t)
|
||||||
|
} else {
|
||||||
|
ExecuteTextEvent(t, eh.buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(t.Deltas) != 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
text := t.Deltas[0].Text
|
||||||
|
start := t.Deltas[0].Start
|
||||||
|
lastnl := -1
|
||||||
|
var endX int
|
||||||
|
var textX int
|
||||||
|
if t.EventType == TextEventInsert {
|
||||||
|
linecount := eh.buf.LinesNum() - oldl
|
||||||
|
textcount := utf8.RuneCount(text)
|
||||||
|
lastnl = bytes.LastIndex(text, []byte{'\n'})
|
||||||
|
if lastnl >= 0 {
|
||||||
|
endX = utf8.RuneCount(text[lastnl+1:])
|
||||||
|
textX = endX
|
||||||
|
} else {
|
||||||
|
endX = start.X + textcount
|
||||||
|
textX = textcount
|
||||||
|
}
|
||||||
|
t.Deltas[0].End = clamp(Loc{endX, start.Y + linecount}, eh.buf.LineArray)
|
||||||
|
}
|
||||||
|
end := t.Deltas[0].End
|
||||||
|
|
||||||
|
for _, c := range eh.cursors {
|
||||||
|
move := func(loc Loc) Loc {
|
||||||
|
if t.EventType == TextEventInsert {
|
||||||
|
if start.Y != loc.Y && loc.GreaterThan(start) {
|
||||||
|
loc.Y += end.Y - start.Y
|
||||||
|
} else if loc.Y == start.Y && loc.GreaterEqual(start) {
|
||||||
|
loc.Y += end.Y - start.Y
|
||||||
|
if lastnl >= 0 {
|
||||||
|
loc.X += textX - start.X
|
||||||
|
} else {
|
||||||
|
loc.X += textX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loc
|
||||||
|
} else {
|
||||||
|
if loc.Y != end.Y && loc.GreaterThan(end) {
|
||||||
|
loc.Y -= end.Y - start.Y
|
||||||
|
} else if loc.Y == end.Y && loc.GreaterEqual(end) {
|
||||||
|
loc = loc.MoveLA(-DiffLA(start, end, eh.buf.LineArray), eh.buf.LineArray)
|
||||||
|
}
|
||||||
|
return loc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.Loc = move(c.Loc)
|
||||||
|
c.CurSelection[0] = move(c.CurSelection[0])
|
||||||
|
c.CurSelection[1] = move(c.CurSelection[1])
|
||||||
|
c.OrigSelection[0] = move(c.OrigSelection[0])
|
||||||
|
c.OrigSelection[1] = move(c.OrigSelection[1])
|
||||||
|
c.Relocate()
|
||||||
|
c.LastVisualX = c.GetVisualX()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ExecuteTextEvent runs a text event
|
// ExecuteTextEvent runs a text event
|
||||||
func ExecuteTextEvent(t *TextEvent, buf *SharedBuffer) {
|
func ExecuteTextEvent(t *TextEvent, buf *SharedBuffer) {
|
||||||
if t.EventType == TextEventInsert {
|
if t.EventType == TextEventInsert {
|
||||||
@@ -66,9 +132,9 @@ func ExecuteTextEvent(t *TextEvent, buf *SharedBuffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UndoTextEvent undoes a text event
|
// UndoTextEvent undoes a text event
|
||||||
func UndoTextEvent(t *TextEvent, buf *SharedBuffer) {
|
func (eh *EventHandler) UndoTextEvent(t *TextEvent) {
|
||||||
t.EventType = -t.EventType
|
t.EventType = -t.EventType
|
||||||
ExecuteTextEvent(t, buf)
|
eh.DoTextEvent(t, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EventHandler executes text manipulations and allows undoing and redoing
|
// EventHandler executes text manipulations and allows undoing and redoing
|
||||||
@@ -118,78 +184,33 @@ func (eh *EventHandler) Insert(start Loc, textStr string) {
|
|||||||
|
|
||||||
// InsertBytes creates an insert text event and executes it
|
// InsertBytes creates an insert text event and executes it
|
||||||
func (eh *EventHandler) InsertBytes(start Loc, text []byte) {
|
func (eh *EventHandler) InsertBytes(start Loc, text []byte) {
|
||||||
|
if len(text) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
start = clamp(start, eh.buf.LineArray)
|
||||||
e := &TextEvent{
|
e := &TextEvent{
|
||||||
C: *eh.cursors[eh.active],
|
C: *eh.cursors[eh.active],
|
||||||
EventType: TextEventInsert,
|
EventType: TextEventInsert,
|
||||||
Deltas: []Delta{{text, start, Loc{0, 0}}},
|
Deltas: []Delta{{text, start, Loc{0, 0}}},
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
}
|
}
|
||||||
// oldl := eh.buf.LinesNum()
|
eh.DoTextEvent(e, true)
|
||||||
eh.Execute(e)
|
|
||||||
// linecount := eh.buf.LinesNum() - oldl
|
|
||||||
textcount := utf8.RuneCount(text)
|
|
||||||
lastnl := bytes.LastIndex(text, []byte{'\n'})
|
|
||||||
var endX int
|
|
||||||
var textX int
|
|
||||||
if lastnl >= 0 {
|
|
||||||
endX = utf8.RuneCount(text[lastnl:])
|
|
||||||
textX = endX
|
|
||||||
} else {
|
|
||||||
// endX = start.X + textcount
|
|
||||||
textX = textcount
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Deltas[0].End = start.MoveLA(textcount, eh.buf.LineArray)
|
|
||||||
// e.Deltas[0].End = clamp(Loc{endX, start.Y + linecount}, eh.buf.LineArray)
|
|
||||||
end := e.Deltas[0].End
|
|
||||||
|
|
||||||
for _, c := range eh.cursors {
|
|
||||||
move := func(loc Loc) Loc {
|
|
||||||
log.Println("move", loc)
|
|
||||||
if start.Y != end.Y && loc.GreaterThan(start) {
|
|
||||||
loc.Y += end.Y - start.Y
|
|
||||||
} else if loc.Y == start.Y && loc.GreaterEqual(start) {
|
|
||||||
loc.Y += end.Y - start.Y
|
|
||||||
loc.X += textX
|
|
||||||
}
|
|
||||||
return loc
|
|
||||||
}
|
|
||||||
c.Loc = move(c.Loc)
|
|
||||||
c.Relocate()
|
|
||||||
c.CurSelection[0] = move(c.CurSelection[0])
|
|
||||||
c.CurSelection[1] = move(c.CurSelection[1])
|
|
||||||
c.OrigSelection[0] = move(c.OrigSelection[0])
|
|
||||||
c.OrigSelection[1] = move(c.OrigSelection[1])
|
|
||||||
c.LastVisualX = c.GetVisualX()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove creates a remove text event and executes it
|
// Remove creates a remove text event and executes it
|
||||||
func (eh *EventHandler) Remove(start, end Loc) {
|
func (eh *EventHandler) Remove(start, end Loc) {
|
||||||
|
if start == end {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
start = clamp(start, eh.buf.LineArray)
|
||||||
|
end = clamp(end, eh.buf.LineArray)
|
||||||
e := &TextEvent{
|
e := &TextEvent{
|
||||||
C: *eh.cursors[eh.active],
|
C: *eh.cursors[eh.active],
|
||||||
EventType: TextEventRemove,
|
EventType: TextEventRemove,
|
||||||
Deltas: []Delta{{[]byte{}, start, end}},
|
Deltas: []Delta{{[]byte{}, start, end}},
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
}
|
}
|
||||||
eh.Execute(e)
|
eh.DoTextEvent(e, true)
|
||||||
|
|
||||||
for _, c := range eh.cursors {
|
|
||||||
move := func(loc Loc) Loc {
|
|
||||||
if start.Y != end.Y && loc.GreaterThan(end) {
|
|
||||||
loc.Y -= end.Y - start.Y
|
|
||||||
} else if loc.Y == end.Y && loc.GreaterEqual(end) {
|
|
||||||
loc = loc.MoveLA(-DiffLA(start, end, eh.buf.LineArray), eh.buf.LineArray)
|
|
||||||
}
|
|
||||||
return loc
|
|
||||||
}
|
|
||||||
c.Loc = move(c.Loc)
|
|
||||||
c.CurSelection[0] = move(c.CurSelection[0])
|
|
||||||
c.CurSelection[1] = move(c.CurSelection[1])
|
|
||||||
c.OrigSelection[0] = move(c.OrigSelection[0])
|
|
||||||
c.OrigSelection[1] = move(c.OrigSelection[1])
|
|
||||||
c.LastVisualX = c.GetVisualX()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MultipleReplace creates an multiple insertions executes them
|
// MultipleReplace creates an multiple insertions executes them
|
||||||
@@ -249,6 +270,7 @@ func (eh *EventHandler) Undo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
eh.UndoOneEvent()
|
eh.UndoOneEvent()
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,10 +282,9 @@ func (eh *EventHandler) UndoOneEvent() {
|
|||||||
if t == nil {
|
if t == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Undo it
|
// Undo it
|
||||||
// Modifies the text event
|
// Modifies the text event
|
||||||
UndoTextEvent(t, eh.buf)
|
eh.UndoTextEvent(t)
|
||||||
|
|
||||||
// Set the cursor in the right place
|
// Set the cursor in the right place
|
||||||
teCursor := t.C
|
teCursor := t.C
|
||||||
@@ -299,6 +320,7 @@ func (eh *EventHandler) Redo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
eh.RedoOneEvent()
|
eh.RedoOneEvent()
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,9 +331,6 @@ func (eh *EventHandler) RedoOneEvent() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modifies the text event
|
|
||||||
UndoTextEvent(t, eh.buf)
|
|
||||||
|
|
||||||
teCursor := t.C
|
teCursor := t.C
|
||||||
if teCursor.Num >= 0 && teCursor.Num < len(eh.cursors) {
|
if teCursor.Num >= 0 && teCursor.Num < len(eh.cursors) {
|
||||||
t.C = *eh.cursors[teCursor.Num]
|
t.C = *eh.cursors[teCursor.Num]
|
||||||
@@ -320,5 +339,8 @@ func (eh *EventHandler) RedoOneEvent() {
|
|||||||
teCursor.Num = -1
|
teCursor.Num = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Modifies the text event
|
||||||
|
eh.UndoTextEvent(t)
|
||||||
|
|
||||||
eh.UndoStack.Push(t)
|
eh.UndoStack.Push(t)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -230,9 +230,7 @@ func (la *LineArray) remove(start, end Loc) []byte {
|
|||||||
if start.Y == end.Y {
|
if start.Y == end.Y {
|
||||||
la.lines[start.Y].data = append(la.lines[start.Y].data[:startX], la.lines[start.Y].data[endX:]...)
|
la.lines[start.Y].data = append(la.lines[start.Y].data[:startX], la.lines[start.Y].data[endX:]...)
|
||||||
} else {
|
} else {
|
||||||
for i := start.Y + 1; i <= end.Y-1; i++ {
|
la.deleteLines(start.Y+1, end.Y-1)
|
||||||
la.deleteLine(start.Y + 1)
|
|
||||||
}
|
|
||||||
la.deleteToEnd(Loc{startX, start.Y})
|
la.deleteToEnd(Loc{startX, start.Y})
|
||||||
la.deleteFromStart(Loc{endX - 1, start.Y + 1})
|
la.deleteFromStart(Loc{endX - 1, start.Y + 1})
|
||||||
la.joinLines(start.Y, start.Y+1)
|
la.joinLines(start.Y, start.Y+1)
|
||||||
@@ -255,6 +253,10 @@ func (la *LineArray) deleteLine(y int) {
|
|||||||
la.lines = la.lines[:y+copy(la.lines[y:], la.lines[y+1:])]
|
la.lines = la.lines[:y+copy(la.lines[y:], la.lines[y+1:])]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (la *LineArray) deleteLines(y1, y2 int) {
|
||||||
|
la.lines = la.lines[:y1+copy(la.lines[y1:], la.lines[y2+1:])]
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteByte deletes the byte at a position
|
// DeleteByte deletes the byte at a position
|
||||||
func (la *LineArray) deleteByte(pos Loc) {
|
func (la *LineArray) deleteByte(pos Loc) {
|
||||||
la.lines[pos.Y].data = la.lines[pos.Y].data[:pos.X+copy(la.lines[pos.Y].data[pos.X:], la.lines[pos.Y].data[pos.X+1:])]
|
la.lines[pos.Y].data = la.lines[pos.Y].data[:pos.X+copy(la.lines[pos.Y].data[pos.X:], la.lines[pos.Y].data[pos.X+1:])]
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ func (l Loc) left(buf *LineArray) Loc {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move moves the cursor n characters to the left or right
|
// MoveLA moves the cursor n characters to the left or right
|
||||||
// It moves the cursor left if n is negative
|
// It moves the cursor left if n is negative
|
||||||
func (l Loc) MoveLA(n int, buf *LineArray) Loc {
|
func (l Loc) MoveLA(n int, buf *LineArray) Loc {
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
@@ -117,9 +117,12 @@ func (l Loc) MoveLA(n int, buf *LineArray) Loc {
|
|||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l Loc) Diff(a, b Loc, buf *Buffer) int {
|
// Diff returns the difference between two locs
|
||||||
return DiffLA(a, b, buf.LineArray)
|
func (l Loc) Diff(b Loc, buf *Buffer) int {
|
||||||
|
return DiffLA(l, b, buf.LineArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move moves a loc n characters
|
||||||
func (l Loc) Move(n int, buf *Buffer) Loc {
|
func (l Loc) Move(n int, buf *Buffer) Loc {
|
||||||
return l.MoveLA(n, buf.LineArray)
|
return l.MoveLA(n, buf.LineArray)
|
||||||
}
|
}
|
||||||
@@ -139,7 +142,7 @@ func ByteOffset(pos Loc, buf *Buffer) int {
|
|||||||
// clamps a loc within a buffer
|
// clamps a loc within a buffer
|
||||||
func clamp(pos Loc, la *LineArray) Loc {
|
func clamp(pos Loc, la *LineArray) Loc {
|
||||||
if pos.GreaterEqual(la.End()) {
|
if pos.GreaterEqual(la.End()) {
|
||||||
return la.End().MoveLA(-1, la)
|
return la.End()
|
||||||
} else if pos.LessThan(la.Start()) {
|
} else if pos.LessThan(la.Start()) {
|
||||||
return la.Start()
|
return la.Start()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package buffer
|
package buffer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
@@ -55,8 +56,9 @@ func overwriteFile(name string, enc encoding.Encoding, fn func(io.Writer) error,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w := transform.NewWriter(writeCloser, enc.NewEncoder())
|
w := bufio.NewWriter(transform.NewWriter(writeCloser, enc.NewEncoder()))
|
||||||
err = fn(w)
|
err = fn(w)
|
||||||
|
w.Flush()
|
||||||
|
|
||||||
if e := writeCloser.Close(); e != nil && err == nil {
|
if e := writeCloser.Close(); e != nil && err == nil {
|
||||||
err = e
|
err = e
|
||||||
@@ -109,8 +111,8 @@ func (b *Buffer) saveToFile(filename string, withSudo bool) error {
|
|||||||
|
|
||||||
if b.Settings["eofnewline"].(bool) {
|
if b.Settings["eofnewline"].(bool) {
|
||||||
end := b.End()
|
end := b.End()
|
||||||
if b.RuneAt(Loc{end.X - 1, end.Y}) != '\n' {
|
if b.RuneAt(Loc{end.X, end.Y}) != '\n' {
|
||||||
b.Insert(end, "\n")
|
b.insert(end, []byte{'\n'})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -120,24 +120,27 @@ func (b *Buffer) FindNext(s string, start, end, from Loc, down bool, useRegex bo
|
|||||||
if down {
|
if down {
|
||||||
l, found = b.findDown(r, from, end)
|
l, found = b.findDown(r, from, end)
|
||||||
if !found {
|
if !found {
|
||||||
l, found = b.findDown(r, start, from)
|
l, found = b.findDown(r, start, end)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
l, found = b.findUp(r, from, start)
|
l, found = b.findUp(r, from, start)
|
||||||
if !found {
|
if !found {
|
||||||
l, found = b.findUp(r, end, from)
|
l, found = b.findUp(r, end, start)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return l, found, nil
|
return l, found, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplaceRegex replaces all occurrences of 'search' with 'replace' in the given area
|
// ReplaceRegex replaces all occurrences of 'search' with 'replace' in the given area
|
||||||
// and returns the number of replacements made
|
// and returns the number of replacements made and the number of runes
|
||||||
func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []byte) int {
|
// added or removed
|
||||||
|
func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []byte) (int, int) {
|
||||||
if start.GreaterThan(end) {
|
if start.GreaterThan(end) {
|
||||||
start, end = end, start
|
start, end = end, start
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netrunes := 0
|
||||||
|
|
||||||
found := 0
|
found := 0
|
||||||
var deltas []Delta
|
var deltas []Delta
|
||||||
for i := start.Y; i <= end.Y; i++ {
|
for i := start.Y; i <= end.Y; i++ {
|
||||||
@@ -155,8 +158,13 @@ func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []b
|
|||||||
l = util.SliceStart(l, end.X)
|
l = util.SliceStart(l, end.X)
|
||||||
}
|
}
|
||||||
newText := search.ReplaceAllFunc(l, func(in []byte) []byte {
|
newText := search.ReplaceAllFunc(l, func(in []byte) []byte {
|
||||||
|
result := []byte{}
|
||||||
|
for _, submatches := range search.FindAllSubmatchIndex(in, -1) {
|
||||||
|
result = search.Expand(result, replace, in, submatches)
|
||||||
|
}
|
||||||
found++
|
found++
|
||||||
return replace
|
netrunes += utf8.RuneCount(in) - utf8.RuneCount(result)
|
||||||
|
return result
|
||||||
})
|
})
|
||||||
|
|
||||||
from := Loc{charpos, i}
|
from := Loc{charpos, i}
|
||||||
@@ -166,5 +174,5 @@ func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []b
|
|||||||
}
|
}
|
||||||
b.MultipleReplace(deltas)
|
b.MultipleReplace(deltas)
|
||||||
|
|
||||||
return found
|
return found, netrunes
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ func (b *Buffer) Serialize() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
name := config.ConfigDir + "/buffers/" + util.EscapePath(b.AbsPath)
|
name := filepath.Join(config.ConfigDir, "buffers", util.EscapePath(b.AbsPath))
|
||||||
|
|
||||||
return overwriteFile(name, encoding.Nop, func(file io.Writer) error {
|
return overwriteFile(name, encoding.Nop, func(file io.Writer) error {
|
||||||
err := gob.NewEncoder(file).Encode(SerializedBuffer{
|
err := gob.NewEncoder(file).Encode(SerializedBuffer{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package config
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
homedir "github.com/mitchellh/go-homedir"
|
homedir "github.com/mitchellh/go-homedir"
|
||||||
)
|
)
|
||||||
@@ -24,10 +25,10 @@ func InitConfigDir(flagConfigDir string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("Error finding your home directory\nCan't load config files: " + err.Error())
|
return errors.New("Error finding your home directory\nCan't load config files: " + err.Error())
|
||||||
}
|
}
|
||||||
xdgHome = home + "/.config"
|
xdgHome = filepath.Join(home, ".config")
|
||||||
}
|
}
|
||||||
|
|
||||||
microHome = xdgHome + "/micro"
|
microHome = filepath.Join(xdgHome, "micro")
|
||||||
}
|
}
|
||||||
ConfigDir = microHome
|
ConfigDir = microHome
|
||||||
|
|
||||||
|
|||||||
@@ -199,7 +199,6 @@ func InitRuntimeFiles() {
|
|||||||
}
|
}
|
||||||
p.Info, err = NewPluginInfo(data)
|
p.Info, err = NewPluginInfo(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p.Name = p.Info.Name
|
p.Name = p.Info.Name
|
||||||
@@ -232,7 +231,6 @@ func InitRuntimeFiles() {
|
|||||||
}
|
}
|
||||||
p.Info, err = NewPluginInfo(data)
|
p.Info, err = NewPluginInfo(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p.Name = p.Info.Name
|
p.Name = p.Info.Name
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -147,7 +147,7 @@ func RegisterCommonOptionPlug(pl string, name string, defaultvalue interface{})
|
|||||||
if v, ok := GlobalSettings[name]; !ok {
|
if v, ok := GlobalSettings[name]; !ok {
|
||||||
defaultCommonSettings[name] = defaultvalue
|
defaultCommonSettings[name] = defaultvalue
|
||||||
GlobalSettings[name] = defaultvalue
|
GlobalSettings[name] = defaultvalue
|
||||||
err := WriteSettings(filepath.Join(ConfigDir, "/settings.json"))
|
err := WriteSettings(filepath.Join(ConfigDir, "settings.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("Error writing settings.json file: " + err.Error())
|
return errors.New("Error writing settings.json file: " + err.Error())
|
||||||
}
|
}
|
||||||
@@ -165,14 +165,14 @@ func RegisterGlobalOptionPlug(pl string, name string, defaultvalue interface{})
|
|||||||
// RegisterGlobalOption creates a new global-only option
|
// RegisterGlobalOption creates a new global-only option
|
||||||
func RegisterGlobalOption(name string, defaultvalue interface{}) error {
|
func RegisterGlobalOption(name string, defaultvalue interface{}) error {
|
||||||
if v, ok := GlobalSettings[name]; !ok {
|
if v, ok := GlobalSettings[name]; !ok {
|
||||||
defaultGlobalSettings[name] = defaultvalue
|
DefaultGlobalOnlySettings[name] = defaultvalue
|
||||||
GlobalSettings[name] = defaultvalue
|
GlobalSettings[name] = defaultvalue
|
||||||
err := WriteSettings(filepath.Join(ConfigDir, "settings.json"))
|
err := WriteSettings(filepath.Join(ConfigDir, "settings.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("Error writing settings.json file: " + err.Error())
|
return errors.New("Error writing settings.json file: " + err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
defaultGlobalSettings[name] = v
|
DefaultGlobalOnlySettings[name] = v
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -184,13 +184,15 @@ func GetGlobalOption(name string) interface{} {
|
|||||||
|
|
||||||
var defaultCommonSettings = map[string]interface{}{
|
var defaultCommonSettings = map[string]interface{}{
|
||||||
"autoindent": true,
|
"autoindent": true,
|
||||||
|
"autosu": false,
|
||||||
"backup": true,
|
"backup": true,
|
||||||
"basename": false,
|
"basename": false,
|
||||||
"colorcolumn": float64(0),
|
"colorcolumn": float64(0),
|
||||||
"cursorline": true,
|
"cursorline": true,
|
||||||
|
"diffgutter": false,
|
||||||
"encoding": "utf-8",
|
"encoding": "utf-8",
|
||||||
"eofnewline": false,
|
"eofnewline": true,
|
||||||
"fastdirty": true,
|
"fastdirty": false,
|
||||||
"fileformat": "unix",
|
"fileformat": "unix",
|
||||||
"filetype": "unknown",
|
"filetype": "unknown",
|
||||||
"ignorecase": false,
|
"ignorecase": false,
|
||||||
@@ -243,7 +245,7 @@ func DefaultCommonSettings() map[string]interface{} {
|
|||||||
|
|
||||||
// a list of settings that should only be globally modified and their
|
// a list of settings that should only be globally modified and their
|
||||||
// default values
|
// default values
|
||||||
var defaultGlobalSettings = map[string]interface{}{
|
var DefaultGlobalOnlySettings = map[string]interface{}{
|
||||||
"autosave": float64(0),
|
"autosave": float64(0),
|
||||||
"colorscheme": "default",
|
"colorscheme": "default",
|
||||||
"infobar": true,
|
"infobar": true,
|
||||||
@@ -254,6 +256,7 @@ var defaultGlobalSettings = map[string]interface{}{
|
|||||||
"sucmd": "sudo",
|
"sucmd": "sudo",
|
||||||
"pluginchannels": []string{"https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json"},
|
"pluginchannels": []string{"https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json"},
|
||||||
"pluginrepos": []string{},
|
"pluginrepos": []string{},
|
||||||
|
"xterm": false,
|
||||||
}
|
}
|
||||||
|
|
||||||
// a list of settings that should never be globally modified
|
// a list of settings that should never be globally modified
|
||||||
@@ -269,7 +272,7 @@ func DefaultGlobalSettings() map[string]interface{} {
|
|||||||
for k, v := range defaultCommonSettings {
|
for k, v := range defaultCommonSettings {
|
||||||
globalsettings[k] = v
|
globalsettings[k] = v
|
||||||
}
|
}
|
||||||
for k, v := range defaultGlobalSettings {
|
for k, v := range DefaultGlobalOnlySettings {
|
||||||
globalsettings[k] = v
|
globalsettings[k] = v
|
||||||
}
|
}
|
||||||
return globalsettings
|
return globalsettings
|
||||||
@@ -282,7 +285,7 @@ func DefaultAllSettings() map[string]interface{} {
|
|||||||
for k, v := range defaultCommonSettings {
|
for k, v := range defaultCommonSettings {
|
||||||
allsettings[k] = v
|
allsettings[k] = v
|
||||||
}
|
}
|
||||||
for k, v := range defaultGlobalSettings {
|
for k, v := range DefaultGlobalOnlySettings {
|
||||||
allsettings[k] = v
|
allsettings[k] = v
|
||||||
}
|
}
|
||||||
return allsettings
|
return allsettings
|
||||||
|
|||||||
@@ -136,9 +136,6 @@ func (w *BufWindow) Relocate() bool {
|
|||||||
if w.drawStatus {
|
if w.drawStatus {
|
||||||
h--
|
h--
|
||||||
}
|
}
|
||||||
if b.LinesNum() <= h {
|
|
||||||
height = w.Height
|
|
||||||
}
|
|
||||||
ret := false
|
ret := false
|
||||||
activeC := w.Buf.GetActiveCursor()
|
activeC := w.Buf.GetActiveCursor()
|
||||||
cy := activeC.Y
|
cy := activeC.Y
|
||||||
@@ -212,6 +209,9 @@ func (w *BufWindow) LocFromVisual(svloc buffer.Loc) buffer.Loc {
|
|||||||
if hasMessage {
|
if hasMessage {
|
||||||
vloc.X += 2
|
vloc.X += 2
|
||||||
}
|
}
|
||||||
|
if b.Settings["diffgutter"].(bool) {
|
||||||
|
vloc.X++
|
||||||
|
}
|
||||||
if b.Settings["ruler"].(bool) {
|
if b.Settings["ruler"].(bool) {
|
||||||
vloc.X += maxLineNumLength + 1
|
vloc.X += maxLineNumLength + 1
|
||||||
}
|
}
|
||||||
@@ -272,11 +272,7 @@ func (w *BufWindow) LocFromVisual(svloc buffer.Loc) buffer.Loc {
|
|||||||
if vloc.Y >= bufHeight {
|
if vloc.Y >= bufHeight {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
vloc.X = 0
|
vloc.X = w.gutterOffset
|
||||||
// This will draw an empty line number because the current line is wrapped
|
|
||||||
if b.Settings["ruler"].(bool) {
|
|
||||||
vloc.X += maxLineNumLength + 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -311,6 +307,34 @@ func (w *BufWindow) drawGutter(vloc *buffer.Loc, bloc *buffer.Loc) {
|
|||||||
vloc.X++
|
vloc.X++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *BufWindow) drawDiffGutter(backgroundStyle tcell.Style, softwrapped bool, vloc *buffer.Loc, bloc *buffer.Loc) {
|
||||||
|
symbol := ' '
|
||||||
|
styleName := ""
|
||||||
|
|
||||||
|
switch w.Buf.DiffStatus(bloc.Y) {
|
||||||
|
case buffer.DSAdded:
|
||||||
|
symbol = '\u258C' // Left half block
|
||||||
|
styleName = "diff-added"
|
||||||
|
case buffer.DSModified:
|
||||||
|
symbol = '\u258C' // Left half block
|
||||||
|
styleName = "diff-modified"
|
||||||
|
case buffer.DSDeletedAbove:
|
||||||
|
if !softwrapped {
|
||||||
|
symbol = '\u2594' // Upper one eighth block
|
||||||
|
styleName = "diff-deleted"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
style := backgroundStyle
|
||||||
|
if s, ok := config.Colorscheme[styleName]; ok {
|
||||||
|
foreground, _, _ := s.Decompose()
|
||||||
|
style = style.Foreground(foreground)
|
||||||
|
}
|
||||||
|
|
||||||
|
screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, symbol, nil, style)
|
||||||
|
vloc.X++
|
||||||
|
}
|
||||||
|
|
||||||
func (w *BufWindow) drawLineNum(lineNumStyle tcell.Style, softwrapped bool, maxLineNumLength int, vloc *buffer.Loc, bloc *buffer.Loc) {
|
func (w *BufWindow) drawLineNum(lineNumStyle tcell.Style, softwrapped bool, maxLineNumLength int, vloc *buffer.Loc, bloc *buffer.Loc) {
|
||||||
lineNum := strconv.Itoa(bloc.Y + 1)
|
lineNum := strconv.Itoa(bloc.Y + 1)
|
||||||
|
|
||||||
@@ -373,15 +397,22 @@ func (w *BufWindow) displayBuffer() {
|
|||||||
bufWidth--
|
bufWidth--
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.Settings["syntax"].(bool) && b.SyntaxDef != nil {
|
if b.ModifiedThisFrame {
|
||||||
for _, r := range b.Modifications {
|
if b.Settings["diffgutter"].(bool) {
|
||||||
final := -1
|
b.UpdateDiff(func(synchronous bool) {
|
||||||
for i := r.X; i <= r.Y; i++ {
|
// If the diff was updated asynchronously, the outer call to
|
||||||
final = util.Max(b.Highlighter.ReHighlightStates(b, i), final)
|
// displayBuffer might already be completed and we need to
|
||||||
}
|
// schedule a redraw in order to display the new diff.
|
||||||
b.Highlighter.HighlightMatches(b, r.X, final+1)
|
// Note that this cannot lead to an infinite recursion
|
||||||
|
// because the modifications were cleared above so there won't
|
||||||
|
// be another call to UpdateDiff when displayBuffer is called
|
||||||
|
// during the redraw.
|
||||||
|
if !synchronous {
|
||||||
|
screen.Redraw()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
b.ClearModifications()
|
b.ModifiedThisFrame = false
|
||||||
}
|
}
|
||||||
|
|
||||||
var matchingBraces []buffer.Loc
|
var matchingBraces []buffer.Loc
|
||||||
@@ -398,12 +429,14 @@ func (w *BufWindow) displayBuffer() {
|
|||||||
r := c.RuneUnder(curX)
|
r := c.RuneUnder(curX)
|
||||||
rl := c.RuneUnder(curX - 1)
|
rl := c.RuneUnder(curX - 1)
|
||||||
if r == bp[0] || r == bp[1] || rl == bp[0] || rl == bp[1] {
|
if r == bp[0] || r == bp[1] || rl == bp[0] || rl == bp[1] {
|
||||||
mb, left := b.FindMatchingBrace(bp, curLoc)
|
mb, left, found := b.FindMatchingBrace(bp, curLoc)
|
||||||
matchingBraces = append(matchingBraces, mb)
|
if found {
|
||||||
if !left {
|
matchingBraces = append(matchingBraces, mb)
|
||||||
matchingBraces = append(matchingBraces, curLoc)
|
if !left {
|
||||||
} else {
|
matchingBraces = append(matchingBraces, curLoc)
|
||||||
matchingBraces = append(matchingBraces, curLoc.Move(-1, b))
|
} else {
|
||||||
|
matchingBraces = append(matchingBraces, curLoc.Move(-1, b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -444,18 +477,28 @@ func (w *BufWindow) displayBuffer() {
|
|||||||
for vloc.Y = 0; vloc.Y < bufHeight; vloc.Y++ {
|
for vloc.Y = 0; vloc.Y < bufHeight; vloc.Y++ {
|
||||||
vloc.X = 0
|
vloc.X = 0
|
||||||
|
|
||||||
|
currentLine := false
|
||||||
|
for _, c := range cursors {
|
||||||
|
if bloc.Y == c.Y && w.active {
|
||||||
|
currentLine = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s := lineNumStyle
|
||||||
|
if currentLine {
|
||||||
|
s = curNumStyle
|
||||||
|
}
|
||||||
|
|
||||||
if hasMessage {
|
if hasMessage {
|
||||||
w.drawGutter(&vloc, &bloc)
|
w.drawGutter(&vloc, &bloc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if b.Settings["diffgutter"].(bool) {
|
||||||
|
w.drawDiffGutter(s, false, &vloc, &bloc)
|
||||||
|
}
|
||||||
|
|
||||||
if b.Settings["ruler"].(bool) {
|
if b.Settings["ruler"].(bool) {
|
||||||
s := lineNumStyle
|
|
||||||
for _, c := range cursors {
|
|
||||||
if bloc.Y == c.Y && w.active {
|
|
||||||
s = curNumStyle
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.drawLineNum(s, false, maxLineNumLength, &vloc, &bloc)
|
w.drawLineNum(s, false, maxLineNumLength, &vloc, &bloc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,6 +622,13 @@ func (w *BufWindow) displayBuffer() {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
vloc.X = 0
|
vloc.X = 0
|
||||||
|
if hasMessage {
|
||||||
|
w.drawGutter(&vloc, &bloc)
|
||||||
|
}
|
||||||
|
if b.Settings["diffgutter"].(bool) {
|
||||||
|
w.drawDiffGutter(lineNumStyle, true, &vloc, &bloc)
|
||||||
|
}
|
||||||
|
|
||||||
// This will draw an empty line number because the current line is wrapped
|
// This will draw an empty line number because the current line is wrapped
|
||||||
if b.Settings["ruler"].(bool) {
|
if b.Settings["ruler"].(bool) {
|
||||||
w.drawLineNum(lineNumStyle, true, maxLineNumLength, &vloc, &bloc)
|
w.drawLineNum(lineNumStyle, true, maxLineNumLength, &vloc, &bloc)
|
||||||
|
|||||||
@@ -122,10 +122,8 @@ func (i *InfoWindow) displayBuffer() {
|
|||||||
|
|
||||||
totalwidth := blocX - nColsBeforeStart
|
totalwidth := blocX - nColsBeforeStart
|
||||||
for len(line) > 0 {
|
for len(line) > 0 {
|
||||||
if activeC.X == blocX {
|
curVX := vlocX
|
||||||
screen.ShowCursor(vlocX, i.Y)
|
curBX := blocX
|
||||||
}
|
|
||||||
|
|
||||||
r, size := utf8.DecodeRune(line)
|
r, size := utf8.DecodeRune(line)
|
||||||
|
|
||||||
draw(r, i.defStyle())
|
draw(r, i.defStyle())
|
||||||
@@ -151,6 +149,9 @@ func (i *InfoWindow) displayBuffer() {
|
|||||||
draw(char, i.defStyle())
|
draw(char, i.defStyle())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if activeC.X == curBX {
|
||||||
|
screen.ShowCursor(curVX, i.Y)
|
||||||
|
}
|
||||||
totalwidth += width
|
totalwidth += width
|
||||||
if vlocX >= i.Width {
|
if vlocX >= i.Width {
|
||||||
break
|
break
|
||||||
@@ -208,6 +209,7 @@ func (i *InfoWindow) scrollToSuggestion() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *InfoWindow) Display() {
|
func (i *InfoWindow) Display() {
|
||||||
|
i.Clear()
|
||||||
x := 0
|
x := 0
|
||||||
if config.GetGlobalOption("keymenu").(bool) {
|
if config.GetGlobalOption("keymenu").(bool) {
|
||||||
i.displayKeyMenu()
|
i.displayKeyMenu()
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package display
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -32,9 +31,6 @@ type StatusLine struct {
|
|||||||
|
|
||||||
var statusInfo = map[string]func(*buffer.Buffer) string{
|
var statusInfo = map[string]func(*buffer.Buffer) string{
|
||||||
"filename": func(b *buffer.Buffer) string {
|
"filename": func(b *buffer.Buffer) string {
|
||||||
if b.Settings["basename"].(bool) {
|
|
||||||
return path.Base(b.GetName())
|
|
||||||
}
|
|
||||||
return b.GetName()
|
return b.GetName()
|
||||||
},
|
},
|
||||||
"line": func(b *buffer.Buffer) string {
|
"line": func(b *buffer.Buffer) string {
|
||||||
|
|||||||
@@ -14,19 +14,19 @@ type TabWindow struct {
|
|||||||
Names []string
|
Names []string
|
||||||
active int
|
active int
|
||||||
Y int
|
Y int
|
||||||
width int
|
Width int
|
||||||
hscroll int
|
hscroll int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTabWindow(w int, y int) *TabWindow {
|
func NewTabWindow(w int, y int) *TabWindow {
|
||||||
tw := new(TabWindow)
|
tw := new(TabWindow)
|
||||||
tw.width = w
|
tw.Width = w
|
||||||
tw.Y = y
|
tw.Y = y
|
||||||
return tw
|
return tw
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *TabWindow) Resize(width, height int) {
|
func (w *TabWindow) Resize(width, height int) {
|
||||||
w.width = width
|
w.Width = width
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *TabWindow) LocFromVisual(vloc buffer.Loc) int {
|
func (w *TabWindow) LocFromVisual(vloc buffer.Loc) int {
|
||||||
@@ -40,7 +40,7 @@ func (w *TabWindow) LocFromVisual(vloc buffer.Loc) int {
|
|||||||
}
|
}
|
||||||
x += s
|
x += s
|
||||||
x += 3
|
x += 3
|
||||||
if x >= w.width {
|
if x >= w.Width {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,9 +50,9 @@ func (w *TabWindow) LocFromVisual(vloc buffer.Loc) int {
|
|||||||
func (w *TabWindow) Scroll(amt int) {
|
func (w *TabWindow) Scroll(amt int) {
|
||||||
w.hscroll += amt
|
w.hscroll += amt
|
||||||
s := w.TotalSize()
|
s := w.TotalSize()
|
||||||
w.hscroll = util.Clamp(w.hscroll, 0, s-w.width)
|
w.hscroll = util.Clamp(w.hscroll, 0, s-w.Width)
|
||||||
|
|
||||||
if s-w.width <= 0 {
|
if s-w.Width <= 0 {
|
||||||
w.hscroll = 0
|
w.hscroll = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,17 +77,17 @@ func (w *TabWindow) SetActive(a int) {
|
|||||||
for i, n := range w.Names {
|
for i, n := range w.Names {
|
||||||
c := utf8.RuneCountInString(n)
|
c := utf8.RuneCountInString(n)
|
||||||
if i == a {
|
if i == a {
|
||||||
if x+c >= w.hscroll+w.width {
|
if x+c >= w.hscroll+w.Width {
|
||||||
w.hscroll = util.Clamp(x+c+1-w.width, 0, s-w.width)
|
w.hscroll = util.Clamp(x+c+1-w.Width, 0, s-w.Width)
|
||||||
} else if x < w.hscroll {
|
} else if x < w.hscroll {
|
||||||
w.hscroll = util.Clamp(x-4, 0, s-w.width)
|
w.hscroll = util.Clamp(x-4, 0, s-w.Width)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
x += c + 4
|
x += c + 4
|
||||||
}
|
}
|
||||||
|
|
||||||
if s-w.width <= 0 {
|
if s-w.Width <= 0 {
|
||||||
w.hscroll = 0
|
w.hscroll = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,6 +96,11 @@ func (w *TabWindow) Display() {
|
|||||||
x := -w.hscroll
|
x := -w.hscroll
|
||||||
done := false
|
done := false
|
||||||
|
|
||||||
|
tabBarStyle := config.DefStyle.Reverse(true)
|
||||||
|
if style, ok := config.Colorscheme["tabbar"]; ok {
|
||||||
|
tabBarStyle = style
|
||||||
|
}
|
||||||
|
|
||||||
draw := func(r rune, n int) {
|
draw := func(r rune, n int) {
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
rw := runewidth.RuneWidth(r)
|
rw := runewidth.RuneWidth(r)
|
||||||
@@ -104,14 +109,14 @@ func (w *TabWindow) Display() {
|
|||||||
if j > 0 {
|
if j > 0 {
|
||||||
c = ' '
|
c = ' '
|
||||||
}
|
}
|
||||||
if x == w.width-1 && !done {
|
if x == w.Width-1 && !done {
|
||||||
screen.SetContent(w.width-1, w.Y, '>', nil, config.DefStyle.Reverse(true))
|
screen.SetContent(w.Width-1, w.Y, '>', nil, tabBarStyle)
|
||||||
x++
|
x++
|
||||||
break
|
break
|
||||||
} else if x == 0 && w.hscroll > 0 {
|
} else if x == 0 && w.hscroll > 0 {
|
||||||
screen.SetContent(0, w.Y, '<', nil, config.DefStyle.Reverse(true))
|
screen.SetContent(0, w.Y, '<', nil, tabBarStyle)
|
||||||
} else if x >= 0 && x < w.width {
|
} else if x >= 0 && x < w.Width {
|
||||||
screen.SetContent(x, w.Y, c, nil, config.DefStyle.Reverse(true))
|
screen.SetContent(x, w.Y, c, nil, tabBarStyle)
|
||||||
}
|
}
|
||||||
x++
|
x++
|
||||||
}
|
}
|
||||||
@@ -136,12 +141,12 @@ func (w *TabWindow) Display() {
|
|||||||
} else {
|
} else {
|
||||||
draw(' ', 3)
|
draw(' ', 3)
|
||||||
}
|
}
|
||||||
if x >= w.width {
|
if x >= w.Width {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if x < w.width {
|
if x < w.Width {
|
||||||
draw(' ', w.width-x)
|
draw(' ', w.Width-x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package info
|
|||||||
import (
|
import (
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/zyedidia/micro/internal/config"
|
"github.com/zyedidia/micro/internal/config"
|
||||||
)
|
)
|
||||||
@@ -12,7 +13,7 @@ import (
|
|||||||
// The savehistory option must be on
|
// The savehistory option must be on
|
||||||
func (i *InfoBuf) LoadHistory() {
|
func (i *InfoBuf) LoadHistory() {
|
||||||
if config.GetGlobalOption("savehistory").(bool) {
|
if config.GetGlobalOption("savehistory").(bool) {
|
||||||
file, err := os.Open(config.ConfigDir + "/buffers/history")
|
file, err := os.Open(filepath.Join(config.ConfigDir, "buffers", "history"))
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
var decodedMap map[string][]string
|
var decodedMap map[string][]string
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -46,7 +47,7 @@ func (i *InfoBuf) SaveHistory() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := os.Create(config.ConfigDir + "/buffers/history")
|
file, err := os.Create(filepath.Join(config.ConfigDir, "buffers", "history"))
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
encoder := gob.NewEncoder(file)
|
encoder := gob.NewEncoder(file)
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ var Screen tcell.Screen
|
|||||||
// The lock is necessary since the screen is polled on a separate thread
|
// The lock is necessary since the screen is polled on a separate thread
|
||||||
var lock sync.Mutex
|
var lock sync.Mutex
|
||||||
|
|
||||||
// DrawChan is a channel that will cause the screen to redraw when
|
// drawChan is a channel that will cause the screen to redraw when
|
||||||
// written to even if no event user event has occurred
|
// written to even if no event user event has occurred
|
||||||
var DrawChan chan bool
|
var drawChan chan bool
|
||||||
|
|
||||||
// Lock locks the screen lock
|
// Lock locks the screen lock
|
||||||
func Lock() {
|
func Lock() {
|
||||||
@@ -37,7 +37,16 @@ func Unlock() {
|
|||||||
|
|
||||||
// Redraw schedules a redraw with the draw channel
|
// Redraw schedules a redraw with the draw channel
|
||||||
func Redraw() {
|
func Redraw() {
|
||||||
DrawChan <- true
|
select {
|
||||||
|
case drawChan <- true:
|
||||||
|
default:
|
||||||
|
// channel is full
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DrawChan returns the draw channel
|
||||||
|
func DrawChan() chan bool {
|
||||||
|
return drawChan
|
||||||
}
|
}
|
||||||
|
|
||||||
type screenCell struct {
|
type screenCell struct {
|
||||||
@@ -118,7 +127,7 @@ func TempStart(screenWasNil bool) {
|
|||||||
|
|
||||||
// Init creates and initializes the tcell screen
|
// Init creates and initializes the tcell screen
|
||||||
func Init() {
|
func Init() {
|
||||||
DrawChan = make(chan bool, 8)
|
drawChan = make(chan bool)
|
||||||
|
|
||||||
// Should we enable true color?
|
// Should we enable true color?
|
||||||
truecolor := os.Getenv("MICRO_TRUECOLOR") == "1"
|
truecolor := os.Getenv("MICRO_TRUECOLOR") == "1"
|
||||||
@@ -127,6 +136,12 @@ func Init() {
|
|||||||
os.Setenv("TCELL_TRUECOLOR", "disable")
|
os.Setenv("TCELL_TRUECOLOR", "disable")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var oldTerm string
|
||||||
|
if config.GetGlobalOption("xterm").(bool) {
|
||||||
|
oldTerm = os.Getenv("TERM")
|
||||||
|
os.Setenv("TERM", "xterm-256color")
|
||||||
|
}
|
||||||
|
|
||||||
// Initilize tcell
|
// Initilize tcell
|
||||||
var err error
|
var err error
|
||||||
Screen, err = tcell.NewScreen()
|
Screen, err = tcell.NewScreen()
|
||||||
@@ -140,6 +155,11 @@ func Init() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore TERM
|
||||||
|
if config.GetGlobalOption("xterm").(bool) {
|
||||||
|
os.Setenv("TERM", oldTerm)
|
||||||
|
}
|
||||||
|
|
||||||
if config.GetGlobalOption("mouse").(bool) {
|
if config.GetGlobalOption("mouse").(bool) {
|
||||||
Screen.EnableMouse()
|
Screen.EnableMouse()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ var (
|
|||||||
// CompileDate is the date this binary was compiled on
|
// CompileDate is the date this binary was compiled on
|
||||||
CompileDate = "Unknown"
|
CompileDate = "Unknown"
|
||||||
// Debug logging
|
// Debug logging
|
||||||
Debug = "ON"
|
Debug = "OFF"
|
||||||
// FakeCursor is used to disable the terminal cursor and have micro
|
// FakeCursor is used to disable the terminal cursor and have micro
|
||||||
// draw its own (enabled for windows consoles where the cursor is slow)
|
// draw its own (enabled for windows consoles where the cursor is slow)
|
||||||
FakeCursor = false
|
FakeCursor = false
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ color-link tabbar "#1D1F21,#C5C8C6"
|
|||||||
color-link indent-char "#505050,#1D1F21"
|
color-link indent-char "#505050,#1D1F21"
|
||||||
color-link line-number "#656866,#232526"
|
color-link line-number "#656866,#232526"
|
||||||
color-link current-line-number "#656866,#1D1F21"
|
color-link current-line-number "#656866,#1D1F21"
|
||||||
|
color-link diff-added "#00AF00"
|
||||||
|
color-link diff-modified "#FFAF00"
|
||||||
|
color-link diff-deleted "#D70000"
|
||||||
color-link gutter-error "#FF4444,#1D1F21"
|
color-link gutter-error "#FF4444,#1D1F21"
|
||||||
color-link gutter-warning "#EEEE77,#1D1F21"
|
color-link gutter-warning "#EEEE77,#1D1F21"
|
||||||
color-link cursor-line "#2D2F31"
|
color-link cursor-line "#2D2F31"
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ color-link underlined "underline 241,231"
|
|||||||
color-link todo "246,231"
|
color-link todo "246,231"
|
||||||
color-link statusline "241,254"
|
color-link statusline "241,254"
|
||||||
color-link tabbar "241,254"
|
color-link tabbar "241,254"
|
||||||
|
color-link diff-added "34"
|
||||||
|
color-link diff-modified "214"
|
||||||
|
color-link diff-deleted "160"
|
||||||
color-link gutter-error "197,231"
|
color-link gutter-error "197,231"
|
||||||
color-link gutter-warning "134,231"
|
color-link gutter-warning "134,231"
|
||||||
color-link line-number "246,254"
|
color-link line-number "246,254"
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ color-link statusline "white,blue"
|
|||||||
color-link tabbar "white,blue"
|
color-link tabbar "white,blue"
|
||||||
color-link current-line-number "red"
|
color-link current-line-number "red"
|
||||||
color-link current-line-number.scroller "red"
|
color-link current-line-number.scroller "red"
|
||||||
|
color-link diff-added "green"
|
||||||
|
color-link diff-modified "yellow"
|
||||||
|
color-link diff-deleted "red"
|
||||||
color-link gutter-error ",red"
|
color-link gutter-error ",red"
|
||||||
color-link gutter-warning "red"
|
color-link gutter-warning "red"
|
||||||
color-link color-column "cyan"
|
color-link color-column "cyan"
|
||||||
|
|||||||
@@ -28,9 +28,12 @@ color-link statusline "#aaaaaa,#8a496b"
|
|||||||
color-link tabbar "#aaaaaa,#8a496b"
|
color-link tabbar "#aaaaaa,#8a496b"
|
||||||
color-link current-line-number "bold #e34234,#424549"
|
color-link current-line-number "bold #e34234,#424549"
|
||||||
color-link current-line-number.scroller "red"
|
color-link current-line-number.scroller "red"
|
||||||
|
color-link diff-added "#00AF00"
|
||||||
|
color-link diff-modified "#FFAF00"
|
||||||
|
color-link diff-deleted "#D70000"
|
||||||
color-link gutter-error ",#e34234"
|
color-link gutter-error ",#e34234"
|
||||||
color-link gutter-warning "#e34234"
|
color-link gutter-warning "#e34234"
|
||||||
color-link color-column "#f26522"
|
color-link color-column "#f26522"
|
||||||
color-link constant.bool "bold #55ffff"
|
color-link constant.bool "bold #55ffff"
|
||||||
color-link constant.bool.true "bold #85ff85"
|
color-link constant.bool.true "bold #85ff85"
|
||||||
color-link constant.bool.false "bold #ff8585"
|
color-link constant.bool.false "bold #ff8585"
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ color-link tabbar "#242424,#CCCCCC"
|
|||||||
color-link indent-char "#4F4F4F,#242424"
|
color-link indent-char "#4F4F4F,#242424"
|
||||||
color-link line-number "#666666,#2C2C2C"
|
color-link line-number "#666666,#2C2C2C"
|
||||||
color-link current-line-number "#666666,#242424"
|
color-link current-line-number "#666666,#242424"
|
||||||
|
color-link diff-added "#00AF00"
|
||||||
|
color-link diff-modified "#FFAF00"
|
||||||
|
color-link diff-deleted "#D70000"
|
||||||
color-link gutter-error "#CB4B16,#242424"
|
color-link gutter-error "#CB4B16,#242424"
|
||||||
color-link gutter-warning "#E6DB74,#242424"
|
color-link gutter-warning "#E6DB74,#242424"
|
||||||
color-link cursor-line "#2C2C2C"
|
color-link cursor-line "#2C2C2C"
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ color-link tabbar "#282828,#F8F8F2"
|
|||||||
color-link indent-char "#505050,#282828"
|
color-link indent-char "#505050,#282828"
|
||||||
color-link line-number "#AAAAAA,#323232"
|
color-link line-number "#AAAAAA,#323232"
|
||||||
color-link current-line-number "#AAAAAA,#282828"
|
color-link current-line-number "#AAAAAA,#282828"
|
||||||
|
color-link diff-added "#00AF00"
|
||||||
|
color-link diff-modified "#FFAF00"
|
||||||
|
color-link diff-deleted "#D70000"
|
||||||
color-link gutter-error "#CB4B16,#282828"
|
color-link gutter-error "#CB4B16,#282828"
|
||||||
color-link gutter-warning "#E6DB74,#282828"
|
color-link gutter-warning "#E6DB74,#282828"
|
||||||
color-link cursor-line "#323232"
|
color-link cursor-line "#323232"
|
||||||
|
|||||||
@@ -18,5 +18,8 @@ color-link current-line-number ""
|
|||||||
color-link statusline "black,white"
|
color-link statusline "black,white"
|
||||||
color-link tabbar "black,white"
|
color-link tabbar "black,white"
|
||||||
color-link color-column "bold geren"
|
color-link color-column "bold geren"
|
||||||
|
color-link diff-added "green"
|
||||||
|
color-link diff-modified "yellow"
|
||||||
|
color-link diff-deleted "red"
|
||||||
color-link gutter-error ",red"
|
color-link gutter-error ",red"
|
||||||
color-link gutter-warning "red"
|
color-link gutter-warning "red"
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ color-link statusline "#091F2E,#599CAB"
|
|||||||
color-link indent-char "#505050,#0C1014"
|
color-link indent-char "#505050,#0C1014"
|
||||||
color-link line-number "#245361,#11151C"
|
color-link line-number "#245361,#11151C"
|
||||||
color-link current-line-number "#599CAB,#11151C"
|
color-link current-line-number "#599CAB,#11151C"
|
||||||
|
color-link diff-added "#00AF00"
|
||||||
|
color-link diff-modified "#FFAF00"
|
||||||
|
color-link diff-deleted "#D70000"
|
||||||
color-link gutter-error "#C23127,#11151C"
|
color-link gutter-error "#C23127,#11151C"
|
||||||
color-link gutter-warning "#EDB443,#11151C"
|
color-link gutter-warning "#EDB443,#11151C"
|
||||||
color-link cursor-line "#091F2E"
|
color-link cursor-line "#091F2E"
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ color-link type "#fb4934,#282828"
|
|||||||
color-link special "#d79921,#282828"
|
color-link special "#d79921,#282828"
|
||||||
color-link underlined "underline #282828"
|
color-link underlined "underline #282828"
|
||||||
color-link error "#9d0006,#282828"
|
color-link error "#9d0006,#282828"
|
||||||
|
color-link diff-added "#00AF00"
|
||||||
|
color-link diff-modified "#FFAF00"
|
||||||
|
color-link diff-deleted "#D70000"
|
||||||
color-link gutter-error "#fb4934,#282828"
|
color-link gutter-error "#fb4934,#282828"
|
||||||
color-link gutter-warning "#d79921,#282828"
|
color-link gutter-warning "#d79921,#282828"
|
||||||
color-link line-number "#665c54,#3c3836"
|
color-link line-number "#665c54,#3c3836"
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ color-link special "172,235"
|
|||||||
color-link underlined "underline 109,235"
|
color-link underlined "underline 109,235"
|
||||||
color-link error "235,124"
|
color-link error "235,124"
|
||||||
color-link todo "bold 223,235"
|
color-link todo "bold 223,235"
|
||||||
|
color-link diff-added "34"
|
||||||
|
color-link diff-modified "214"
|
||||||
|
color-link diff-deleted "160"
|
||||||
color-link line-number "243,237"
|
color-link line-number "243,237"
|
||||||
color-link current-line-number "172,235"
|
color-link current-line-number "172,235"
|
||||||
color-link cursor-line "237"
|
color-link cursor-line "237"
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ color-link constant.string "#C3E88D,#263238"
|
|||||||
color-link current-line-number "#80DEEA,#263238"
|
color-link current-line-number "#80DEEA,#263238"
|
||||||
color-link cursor-line "#283942"
|
color-link cursor-line "#283942"
|
||||||
color-link default "#EEFFFF,#263238"
|
color-link default "#EEFFFF,#263238"
|
||||||
|
color-link diff-added "#00AF00"
|
||||||
|
color-link diff-modified "#FFAF00"
|
||||||
|
color-link diff-deleted "#D70000"
|
||||||
color-link divider "#263238,#80DEEA"
|
color-link divider "#263238,#80DEEA"
|
||||||
color-link error "bold #263238,#F07178"
|
color-link error "bold #263238,#F07178"
|
||||||
color-link gutter-error "#EEFFFF,#F07178"
|
color-link gutter-error "#EEFFFF,#F07178"
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ color-link statusline "#282828,#F8F8F2"
|
|||||||
color-link indent-char "#505050,#282828"
|
color-link indent-char "#505050,#282828"
|
||||||
color-link line-number "#AAAAAA,#282828"
|
color-link line-number "#AAAAAA,#282828"
|
||||||
color-link current-line-number "#AAAAAA,#1D0000"
|
color-link current-line-number "#AAAAAA,#1D0000"
|
||||||
|
color-link diff-added "#00AF00"
|
||||||
|
color-link diff-modified "#FFAF00"
|
||||||
|
color-link diff-deleted "#D70000"
|
||||||
color-link gutter-error "#CB4B16"
|
color-link gutter-error "#CB4B16"
|
||||||
color-link gutter-warning "#E6DB74"
|
color-link gutter-warning "#E6DB74"
|
||||||
color-link cursor-line "#323232"
|
color-link cursor-line "#323232"
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ color-link tabbar "#282828,#F8F8F2"
|
|||||||
color-link indent-char "#505050,#282828"
|
color-link indent-char "#505050,#282828"
|
||||||
color-link line-number "#AAAAAA,#323232"
|
color-link line-number "#AAAAAA,#323232"
|
||||||
color-link current-line-number "#AAAAAA,#282828"
|
color-link current-line-number "#AAAAAA,#282828"
|
||||||
|
color-link diff-added "#00AF00"
|
||||||
|
color-link diff-modified "#FFAF00"
|
||||||
|
color-link diff-deleted "#D70000"
|
||||||
color-link gutter-error "#CB4B16,#282828"
|
color-link gutter-error "#CB4B16,#282828"
|
||||||
color-link gutter-warning "#E6DB74,#282828"
|
color-link gutter-warning "#E6DB74,#282828"
|
||||||
color-link cursor-line "#323232"
|
color-link cursor-line "#323232"
|
||||||
|
|||||||
@@ -8,8 +8,11 @@ color-link constant.string.char "#BDE6AD"
|
|||||||
color-link constant.specialChar "#DDF2A4"
|
color-link constant.specialChar "#DDF2A4"
|
||||||
color-link current-line-number "#C6C6C6,#21252C"
|
color-link current-line-number "#C6C6C6,#21252C"
|
||||||
color-link cursor-line "#282C34"
|
color-link cursor-line "#282C34"
|
||||||
color-link divider "#1E1E1E"
|
color-link divider "#ABB2BF"
|
||||||
color-link error "#D2A8A1"
|
color-link error "#D2A8A1"
|
||||||
|
color-link diff-added "#00AF00"
|
||||||
|
color-link diff-modified "#FFAF00"
|
||||||
|
color-link diff-deleted "#D70000"
|
||||||
color-link gutter-error "#9B859D"
|
color-link gutter-error "#9B859D"
|
||||||
color-link gutter-warning "#9B859D"
|
color-link gutter-warning "#9B859D"
|
||||||
color-link identifier "#61AFEF"
|
color-link identifier "#61AFEF"
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ color-link gutter-error "#cc7833,#11151C"
|
|||||||
color-link indent-char "#414141,#2b2b2b"
|
color-link indent-char "#414141,#2b2b2b"
|
||||||
color-link line-number "#a1a1a1,#353535"
|
color-link line-number "#a1a1a1,#353535"
|
||||||
color-link current-line-number "#e6e1dc,#2b2b2b"
|
color-link current-line-number "#e6e1dc,#2b2b2b"
|
||||||
|
color-link diff-added "#00AF00"
|
||||||
|
color-link diff-modified "#FFAF00"
|
||||||
|
color-link diff-deleted "#D70000"
|
||||||
color-link gutter-warning "#a5c261,#11151C"
|
color-link gutter-warning "#a5c261,#11151C"
|
||||||
color-link symbol "#edb753,#2b2b2b"
|
color-link symbol "#edb753,#2b2b2b"
|
||||||
color-link identifier "#edb753,#2b2b2b"
|
color-link identifier "#edb753,#2b2b2b"
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ color-link todo ",brightyellow"
|
|||||||
color-link indent-char "black"
|
color-link indent-char "black"
|
||||||
color-link line-number "yellow"
|
color-link line-number "yellow"
|
||||||
color-link current-line-number "red"
|
color-link current-line-number "red"
|
||||||
|
color-link diff-added "green"
|
||||||
|
color-link diff-modified "yellow"
|
||||||
|
color-link diff-deleted "red"
|
||||||
color-link gutter-error ",red"
|
color-link gutter-error ",red"
|
||||||
color-link gutter-warning "red"
|
color-link gutter-warning "red"
|
||||||
#Cursor line causes readability issues. Disabled for now.
|
#Cursor line causes readability issues. Disabled for now.
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ color-link tabbar "#003541,#839496"
|
|||||||
color-link indent-char "#003541,#002833"
|
color-link indent-char "#003541,#002833"
|
||||||
color-link line-number "#586E75,#003541"
|
color-link line-number "#586E75,#003541"
|
||||||
color-link current-line-number "#586E75,#002833"
|
color-link current-line-number "#586E75,#002833"
|
||||||
|
color-link diff-added "#00AF00"
|
||||||
|
color-link diff-modified "#FFAF00"
|
||||||
|
color-link diff-deleted "#D70000"
|
||||||
color-link gutter-error "#003541,#CB4B16"
|
color-link gutter-error "#003541,#CB4B16"
|
||||||
color-link gutter-warning "#CB4B16,#002833"
|
color-link gutter-warning "#CB4B16,#002833"
|
||||||
color-link cursor-line "#003541"
|
color-link cursor-line "#003541"
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ color-link tabbar "black,brightblue"
|
|||||||
color-link indent-char "black"
|
color-link indent-char "black"
|
||||||
color-link line-number "bold brightgreen,black"
|
color-link line-number "bold brightgreen,black"
|
||||||
color-link current-line-number "bold brightgreen,default"
|
color-link current-line-number "bold brightgreen,default"
|
||||||
|
color-link diff-added "green"
|
||||||
|
color-link diff-modified "yellow"
|
||||||
|
color-link diff-deleted "red"
|
||||||
color-link gutter-error "black,brightred"
|
color-link gutter-error "black,brightred"
|
||||||
color-link gutter-warning "brightred,default"
|
color-link gutter-warning "brightred,default"
|
||||||
color-link cursor-line "black"
|
color-link cursor-line "black"
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ color-link statusline "233,229"
|
|||||||
color-link tabbar "233,229"
|
color-link tabbar "233,229"
|
||||||
color-link indent-char "229"
|
color-link indent-char "229"
|
||||||
color-link line-number "244"
|
color-link line-number "244"
|
||||||
|
color-link diff-added "34"
|
||||||
|
color-link diff-modified "214"
|
||||||
|
color-link diff-deleted "160"
|
||||||
color-link gutter-error "88"
|
color-link gutter-error "88"
|
||||||
color-link gutter-warning "88"
|
color-link gutter-warning "88"
|
||||||
color-link cursor-line "229"
|
color-link cursor-line "229"
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ color-link current-line-number "#868686,#1B1B1B"
|
|||||||
color-link cursor-line "#1B1B1B"
|
color-link cursor-line "#1B1B1B"
|
||||||
color-link divider "#1E1E1E"
|
color-link divider "#1E1E1E"
|
||||||
color-link error "#D2A8A1"
|
color-link error "#D2A8A1"
|
||||||
|
color-link diff-added "#00AF00"
|
||||||
|
color-link diff-modified "#FFAF00"
|
||||||
|
color-link diff-deleted "#D70000"
|
||||||
color-link gutter-error "#9B859D"
|
color-link gutter-error "#9B859D"
|
||||||
color-link gutter-warning "#9B859D"
|
color-link gutter-warning "#9B859D"
|
||||||
color-link identifier "#9B703F"
|
color-link identifier "#9B703F"
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ color-link statusline "186,236"
|
|||||||
color-link tabbar "186,236"
|
color-link tabbar "186,236"
|
||||||
color-link indent-char "238,237"
|
color-link indent-char "238,237"
|
||||||
color-link line-number "248,238"
|
color-link line-number "248,238"
|
||||||
|
color-link diff-added "34"
|
||||||
|
color-link diff-modified "214"
|
||||||
|
color-link diff-deleted "160"
|
||||||
color-link gutter-error "237,174"
|
color-link gutter-error "237,174"
|
||||||
color-link gutter-warning "174,237"
|
color-link gutter-warning "174,237"
|
||||||
color-link cursor-line "238"
|
color-link cursor-line "238"
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ set colorscheme twilight
|
|||||||
Micro comes with a number of colorschemes by default. The colorschemes that you
|
Micro comes with a number of colorschemes by default. The colorschemes that you
|
||||||
can display will depend on what kind of color support your terminal has.
|
can display will depend on what kind of color support your terminal has.
|
||||||
|
|
||||||
|
Omit color-link default "[fg color],[bg color]" will make the background color match the terminal's, and transparency if set.
|
||||||
|
|
||||||
Modern terminals tend to have a palette of 16 user-configurable colors (these
|
Modern terminals tend to have a palette of 16 user-configurable colors (these
|
||||||
colors can often be configured in the terminal preferences), and additional
|
colors can often be configured in the terminal preferences), and additional
|
||||||
color support comes in three flavors.
|
color support comes in three flavors.
|
||||||
@@ -93,6 +95,7 @@ variable `MICRO_TRUECOLOR` must be set to 1.
|
|||||||
look its best. Use cmc-16 if your terminal doesn't support true color.
|
look its best. Use cmc-16 if your terminal doesn't support true color.
|
||||||
* `gruvbox-tc`: The true color version of the gruvbox colorscheme
|
* `gruvbox-tc`: The true color version of the gruvbox colorscheme
|
||||||
* `github-tc`: The true color version of the Github colorscheme
|
* `github-tc`: The true color version of the Github colorscheme
|
||||||
|
* `material-tc`: Colorscheme based off of Google's Material Design palette
|
||||||
|
|
||||||
## Creating a Colorscheme
|
## Creating a Colorscheme
|
||||||
|
|
||||||
|
|||||||
@@ -89,8 +89,9 @@ selection, micro's mouse support must first be disabled by turning the
|
|||||||
`mouse` option off. The terminal, unlike micro, has no sense of different
|
`mouse` option off. The terminal, unlike micro, has no sense of different
|
||||||
buffers/splits and what the different characters being displayed are. This
|
buffers/splits and what the different characters being displayed are. This
|
||||||
means that for copying multiple lines using the terminal selection, you
|
means that for copying multiple lines using the terminal selection, you
|
||||||
should first disable line numbers (turn off the `ruler` option), otherwise
|
should first disable line numbers and diff indicators (turn off the `ruler`
|
||||||
they might be part of your selection and copied.
|
and `diffgutter` options), otherwise they might be part of your selection
|
||||||
|
and copied.
|
||||||
|
|
||||||
## Recommendations
|
## Recommendations
|
||||||
|
|
||||||
@@ -103,7 +104,7 @@ The recommended method of copying is the following:
|
|||||||
* If you are working over SSH, use the terminal keybinding
|
* If you are working over SSH, use the terminal keybinding
|
||||||
(Ctrl-Shift-c or Command-c) to perform copies. You must first disable
|
(Ctrl-Shift-c or Command-c) to perform copies. You must first disable
|
||||||
the `mouse` option to perform a terminal selection, and you may wish
|
the `mouse` option to perform a terminal selection, and you may wish
|
||||||
to disable line numbers (`ruler` option) and close other splits. This
|
to disable line numbers and diff indicators (`ruler` and `diffgutter`
|
||||||
method will only be able to copy characters that are displayed on the
|
options) and close other splits. This method will only be able to copy
|
||||||
screen (you will not be able to copy more than one page's worth of
|
characters that are displayed on the screen (you will not be able to
|
||||||
characters).
|
copy more than one page's worth of characters).
|
||||||
|
|||||||
@@ -194,6 +194,8 @@ DuplicateLine
|
|||||||
DeleteLine
|
DeleteLine
|
||||||
IndentSelection
|
IndentSelection
|
||||||
OutdentSelection
|
OutdentSelection
|
||||||
|
OutdentLine
|
||||||
|
IndentLine
|
||||||
Paste
|
Paste
|
||||||
SelectAll
|
SelectAll
|
||||||
OpenFile
|
OpenFile
|
||||||
@@ -210,6 +212,7 @@ EndOfLine
|
|||||||
ParagraphPrevious
|
ParagraphPrevious
|
||||||
ParagraphNext
|
ParagraphNext
|
||||||
ToggleHelp
|
ToggleHelp
|
||||||
|
ToggleDiffGutter
|
||||||
ToggleRuler
|
ToggleRuler
|
||||||
JumpLine
|
JumpLine
|
||||||
ClearStatus
|
ClearStatus
|
||||||
|
|||||||
@@ -16,6 +16,22 @@ Here are the available options:
|
|||||||
|
|
||||||
default value: `true`
|
default value: `true`
|
||||||
|
|
||||||
|
* `autosave`: automatically save the buffer every n seconds, where n is the
|
||||||
|
value of the autosave option. Also when quitting on a modified buffer, micro
|
||||||
|
will automatically save and quit. Be warned, this option saves the buffer
|
||||||
|
without prompting the user, so data may be overwritten. If this option is
|
||||||
|
set to `0`, no autosaving is performed.
|
||||||
|
|
||||||
|
default value: `0`
|
||||||
|
|
||||||
|
* `autosu`: When a file is saved that the user doesn't have permission to
|
||||||
|
modify, micro will ask if the user would like to use super user
|
||||||
|
privileges to save the file. If this option is enabled, micro will
|
||||||
|
automatically attempt to use super user privileges to save without
|
||||||
|
asking the user.
|
||||||
|
|
||||||
|
default value: `false`
|
||||||
|
|
||||||
* `backup`: micro will automatically keep backups of all open buffers. Backups
|
* `backup`: micro will automatically keep backups of all open buffers. Backups
|
||||||
are stored in `~/.config/micro/backups` and are removed when the buffer is
|
are stored in `~/.config/micro/backups` and are removed when the buffer is
|
||||||
closed cleanly. In the case of a system crash or a micro crash, the contents
|
closed cleanly. In the case of a system crash or a micro crash, the contents
|
||||||
@@ -28,8 +44,8 @@ Here are the available options:
|
|||||||
|
|
||||||
default value: `true`
|
default value: `true`
|
||||||
|
|
||||||
* `basename`: in the infobar, show only the basename of the file being edited
|
* `basename`: in the infobar and tabbar, show only the basename of the file
|
||||||
rather than the full path.
|
being edited rather than the full path.
|
||||||
|
|
||||||
default value: `false`
|
default value: `false`
|
||||||
|
|
||||||
@@ -60,14 +76,19 @@ Here are the available options:
|
|||||||
|
|
||||||
default value: `true`
|
default value: `true`
|
||||||
|
|
||||||
|
* `diffgutter`: display diff indicators before lines.
|
||||||
|
|
||||||
|
default value: `false`
|
||||||
|
|
||||||
* `encoding`: the encoding to open and save files with. Supported encodings
|
* `encoding`: the encoding to open and save files with. Supported encodings
|
||||||
are listed at https://www.w3.org/TR/encoding/.
|
are listed at https://www.w3.org/TR/encoding/.
|
||||||
|
|
||||||
default value: `utf-8`
|
default value: `utf-8`
|
||||||
|
|
||||||
* `eofnewline`: micro will automatically add a newline to the file.
|
* `eofnewline`: micro will automatically add a newline to the end of the
|
||||||
|
file if one does not exist.
|
||||||
|
|
||||||
default value: `false`
|
default value: `true`
|
||||||
|
|
||||||
* `fastdirty`: this determines what kind of algorithm micro uses to determine
|
* `fastdirty`: this determines what kind of algorithm micro uses to determine
|
||||||
if a buffer is modified or not. When `fastdirty` is on, micro just uses a
|
if a buffer is modified or not. When `fastdirty` is on, micro just uses a
|
||||||
@@ -75,10 +96,10 @@ Here are the available options:
|
|||||||
This is fast, but can be inaccurate. If `fastdirty` is off, then micro will
|
This is fast, but can be inaccurate. If `fastdirty` is off, then micro will
|
||||||
hash the current buffer against a hash of the original file (created when
|
hash the current buffer against a hash of the original file (created when
|
||||||
the buffer was loaded). This is more accurate but obviously more resource
|
the buffer was loaded). This is more accurate but obviously more resource
|
||||||
intensive. This option is only for people who really care about having
|
intensive. This option will be automatically disabled if the file size
|
||||||
accurate modified status.
|
exceeds 50KB.
|
||||||
|
|
||||||
default value: `true`
|
default value: `false`
|
||||||
|
|
||||||
* `fileformat`: this determines what kind of line endings micro will use for
|
* `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
|
||||||
@@ -151,6 +172,19 @@ Here are the available options:
|
|||||||
|
|
||||||
default value: `false`
|
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.
|
||||||
|
By default, this option points to the official plugin channel hosted on GitHub
|
||||||
|
at https://github.com/micro-editor/plugin-channel.
|
||||||
|
|
||||||
|
default value: `https://raw.githubusercontent.com/micro-editor/plugin-channel
|
||||||
|
/master/channel.json`
|
||||||
|
|
||||||
|
* `pluginrepos`: a list of links to plugin repositories.
|
||||||
|
|
||||||
|
default value: ``
|
||||||
|
|
||||||
* `readonly`: when enabled, disallows edits to the buffer. It is recommended
|
* `readonly`: when enabled, disallows edits to the buffer. It is recommended
|
||||||
to only ever set this option locally using `setlocal`.
|
to only ever set this option locally using `setlocal`.
|
||||||
|
|
||||||
@@ -263,11 +297,33 @@ Here are the available options:
|
|||||||
|
|
||||||
default value: `true`
|
default value: `true`
|
||||||
|
|
||||||
|
* `xterm`: micro will assume that the terminal it is running in conforms to
|
||||||
|
`xterm-256color` regardless of what the `$TERM` variable actually contains.
|
||||||
|
Enabling this option may cause unwanted effects if your terminal in fact
|
||||||
|
does not conform to the `xterm-256color` standard.
|
||||||
|
|
||||||
|
Default value: `false`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Plugin options: all plugins come with a special option to enable or disable
|
Plugin options: all plugins come with a special option to enable or disable
|
||||||
them. The option is a boolean with the same name as the plugin itself.
|
them. The option is a boolean with the same name as the plugin itself.
|
||||||
|
|
||||||
|
By default, the following plugins are provided, each with an option to enable
|
||||||
|
or disable them:
|
||||||
|
|
||||||
|
* `autoclose`: automatically closes brackets, quotes, etc...
|
||||||
|
* `comment`: provides automatic commenting for a number of languages
|
||||||
|
* `ftoptions`: alters some default options depending on the filetype
|
||||||
|
* `linter`: provides extensible linting for many languages
|
||||||
|
* `literate`: provides advanced syntax highlighting for the Literate
|
||||||
|
programming tool.
|
||||||
|
* `status`: provides some extensions to the status line (integration with
|
||||||
|
Git and more).
|
||||||
|
* `diff`: integrates the `diffgutter` option with Git. If you are in a Git
|
||||||
|
directory, the diff gutter will show changes with respect to the most
|
||||||
|
recent Git commit rather than the diff since opening the file.
|
||||||
|
|
||||||
Any option you set in the editor will be saved to the file
|
Any option you set in the editor will be saved to the file
|
||||||
~/.config/micro/settings.json so, in effect, your configuration file will be
|
~/.config/micro/settings.json so, in effect, your configuration file will be
|
||||||
created for you. If you'd like to take your configuration with you to another
|
created for you. If you'd like to take your configuration with you to another
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from the go plugin, which has the following file structure:
|
|||||||
```
|
```
|
||||||
~/.config/micro/plug/go-plugin/
|
~/.config/micro/plug/go-plugin/
|
||||||
go.lua
|
go.lua
|
||||||
info.json
|
repo.json
|
||||||
help/
|
help/
|
||||||
go-plugin.md
|
go-plugin.md
|
||||||
```
|
```
|
||||||
@@ -35,34 +35,6 @@ is unlikely for a plugin to need to add plugin files at runtime or
|
|||||||
syntax header files. No directory structure is enforced but keeping
|
syntax header files. No directory structure is enforced but keeping
|
||||||
runtime files in their own directories is good practice.
|
runtime files in their own directories is good practice.
|
||||||
|
|
||||||
# Info file
|
|
||||||
|
|
||||||
The `info.json` for the Go plugin is the following:
|
|
||||||
|
|
||||||
```
|
|
||||||
{
|
|
||||||
"name": "go",
|
|
||||||
"description": "Go formatting and tool support",
|
|
||||||
"website": "https://github.com/micro-editor/go-plugin",
|
|
||||||
"install": "https://github.com/micro-editor/go-plugin",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"require": [
|
|
||||||
"micro >= 2.0.0"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
All fields are simply interpreted as strings, so the version does not
|
|
||||||
need to be a semantic version, and the dependencies are also only
|
|
||||||
meant to be parsed by humans. The name should be an identifier, and
|
|
||||||
the website should point to a valid website. The install field should
|
|
||||||
provide info about installing the plugin, or point to a website that
|
|
||||||
provides information.
|
|
||||||
|
|
||||||
Note that the name of the plugin is defined by the name field in
|
|
||||||
the `info.json` and not by the installation path. Some functions micro
|
|
||||||
exposes to plugins require passing the name of the plugin.
|
|
||||||
|
|
||||||
## Lua callbacks
|
## Lua callbacks
|
||||||
|
|
||||||
Plugins use Lua but also have access to many functions both from micro
|
Plugins use Lua but also have access to many functions both from micro
|
||||||
@@ -102,16 +74,6 @@ within. This is almost always the current bufpane.
|
|||||||
|
|
||||||
All available actions are listed in the keybindings section of the help.
|
All available actions are listed in the keybindings section of the help.
|
||||||
|
|
||||||
For callbacks to mouse actions, you are also given the event info:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function onMousePress(view, event)
|
|
||||||
local x, y = event:Position()
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
These functions should also return a boolean specifying whether the bufpane
|
These functions should also return a boolean specifying whether the bufpane
|
||||||
should be relocated to the cursor or not after the action is complete.
|
should be relocated to the cursor or not after the action is complete.
|
||||||
|
|
||||||
@@ -141,7 +103,12 @@ The packages and functions are listed below (in Go type signatures):
|
|||||||
`-debug` flag, or binary built with `build-dbg`).
|
`-debug` flag, or binary built with `build-dbg`).
|
||||||
|
|
||||||
- `SetStatusInfoFn(fn string)`: register the given lua function as
|
- `SetStatusInfoFn(fn string)`: register the given lua function as
|
||||||
accessible from the statusline formatting options
|
accessible from the statusline formatting options.
|
||||||
|
|
||||||
|
- `CurPane() *BufPane`: returns the current BufPane, or nil if the
|
||||||
|
current pane is not a BufPane.
|
||||||
|
|
||||||
|
- `CurTab() *Tab`: returns the current tab.
|
||||||
* `micro/config`
|
* `micro/config`
|
||||||
- `MakeCommand(name string, action func(bp *BufPane, args[]string),
|
- `MakeCommand(name string, action func(bp *BufPane, args[]string),
|
||||||
completer buffer.Completer)`:
|
completer buffer.Completer)`:
|
||||||
@@ -424,6 +391,9 @@ There are 6 default plugins that come pre-installed with micro. These are
|
|||||||
programming tool.
|
programming tool.
|
||||||
* `status`: provides some extensions to the status line (integration with
|
* `status`: provides some extensions to the status line (integration with
|
||||||
Git and more).
|
Git and more).
|
||||||
|
* `diff`: integrates the `diffgutter` option with Git. If you are in a Git
|
||||||
|
directory, the diff gutter will show changes with respect to the most
|
||||||
|
recent Git commit rather than the diff since opening the file.
|
||||||
|
|
||||||
See `> help linter`, `> help comment`, and `> help status` for additional
|
See `> help linter`, `> help comment`, and `> help status` for additional
|
||||||
documentation specific to those plugins.
|
documentation specific to those plugins.
|
||||||
|
|||||||
20
runtime/plugins/diff/diff.lua
Normal file
20
runtime/plugins/diff/diff.lua
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
VERSION = "1.0.0"
|
||||||
|
|
||||||
|
local os = import("os")
|
||||||
|
local filepath = import("path/filepath")
|
||||||
|
local shell = import("micro/shell")
|
||||||
|
|
||||||
|
function onBufferOpen(buf)
|
||||||
|
if buf.Settings["diffgutter"] and (not buf.Type.Scratch) and (buf.Path ~= "") then
|
||||||
|
-- check that file exists
|
||||||
|
local _, err = os.Stat(buf.AbsPath)
|
||||||
|
if err == nil then
|
||||||
|
local dirName, fileName = filepath.Split(buf.AbsPath)
|
||||||
|
local diffBase, err = shell.ExecCommand("git", "-C", dirName, "show", "HEAD:./" .. fileName)
|
||||||
|
if err ~= nil then
|
||||||
|
diffBase = buf:Bytes()
|
||||||
|
end
|
||||||
|
buf:SetDiffBase(diffBase)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -66,12 +66,12 @@ the `misspell` linter which checks for misspelled words in a file.
|
|||||||
```lua
|
```lua
|
||||||
local config = import("micro/config")
|
local config = import("micro/config")
|
||||||
|
|
||||||
|
config.RegisterCommonOption("misspell", true)
|
||||||
|
|
||||||
function init()
|
function init()
|
||||||
-- uses the default linter plugin
|
-- uses the default linter plugin
|
||||||
-- matches any filetype
|
-- matches any filetype
|
||||||
linter.makeLinter("misspell", "", "misspell", {"%f"}, "%f:%l:%c: %m", {}, false, true, 0, 0, hasMisspell)
|
linter.makeLinter("misspell", "", "misspell", {"%f"}, "%f:%l:%c: %m", {}, false, true, 0, 0, hasMisspell)
|
||||||
|
|
||||||
config.RegisterCommonOption("misspell", true)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function hasMisspell(buf)
|
function hasMisspell(buf)
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ local filepath = import("path/filepath")
|
|||||||
local shell = import("micro/shell")
|
local shell = import("micro/shell")
|
||||||
local buffer = import("micro/buffer")
|
local buffer = import("micro/buffer")
|
||||||
local config = import("micro/config")
|
local config = import("micro/config")
|
||||||
|
local util = import("micro/util")
|
||||||
|
local os = import("os")
|
||||||
|
|
||||||
local linters = {}
|
local linters = {}
|
||||||
|
|
||||||
@@ -66,7 +68,7 @@ function init()
|
|||||||
makeLinter("gcc", "c", "gcc", {"-fsyntax-only", "-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m")
|
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("gcc", "c++", "gcc", {"-fsyntax-only","-std=c++14", "-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m")
|
||||||
makeLinter("dmd", "d", "dmd", {"-color=off", "-o-", "-w", "-wi", "-c", "%f"}, "%f%(%l%):.+: %m")
|
makeLinter("dmd", "d", "dmd", {"-color=off", "-o-", "-w", "-wi", "-c", "%f"}, "%f%(%l%):.+: %m")
|
||||||
makeLinter("gobuild", "go", "go", {"build", "-o", devnull}, "%f:%l:%c:? %m")
|
makeLinter("gobuild", "go", "go", {"build", "-o", devnull, "%d"}, "%f:%l:%c:? %m")
|
||||||
-- makeLinter("golint", "go", "golint", {"%f"}, "%f:%l:%c: %m")
|
-- makeLinter("golint", "go", "golint", {"%f"}, "%f:%l:%c: %m")
|
||||||
makeLinter("javac", "java", "javac", {"-d", "%d", "%f"}, "%f:%l: error: %m")
|
makeLinter("javac", "java", "javac", {"-d", "%d", "%f"}, "%f:%l: error: %m")
|
||||||
makeLinter("jshint", "javascript", "jshint", {"%f"}, "%f: line %l,.+, %m")
|
makeLinter("jshint", "javascript", "jshint", {"%f"}, "%f: line %l,.+, %m")
|
||||||
@@ -102,7 +104,7 @@ end
|
|||||||
function runLinter(buf)
|
function runLinter(buf)
|
||||||
local ft = buf:FileType()
|
local ft = buf:FileType()
|
||||||
local file = buf.Path
|
local file = buf.Path
|
||||||
local dir = filepath.Dir(file)
|
local dir = "." .. util.RuneStr(os.PathSeparator) .. filepath.Dir(file)
|
||||||
|
|
||||||
for k, v in pairs(linters) do
|
for k, v in pairs(linters) do
|
||||||
local ftmatch = ft == v.filetype
|
local ftmatch = ft == v.filetype
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Micro's syntax files are licensed under the MIT "Expat" License:
|
Micro's syntax files are licensed under the MIT "Expat" License:
|
||||||
|
|
||||||
Copyright (c) 2016: Zachary Yedidia, Collin Warren, et al.
|
Copyright (c) 2020: Zachary Yedidia, et al.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ rules:
|
|||||||
|
|
||||||
# Data constructors
|
# Data constructors
|
||||||
- constant.bool: "\\b(True|False)\\b"
|
- constant.bool: "\\b(True|False)\\b"
|
||||||
- constant: "(Nothing|Just|Left|Right|LT|EQ|GT)"
|
- constant: "\\b(Nothing|Just|Left|Right|LT|EQ|GT)\\b"
|
||||||
|
|
||||||
# Data classes
|
# Data classes
|
||||||
- identifier.class: "[ ](Read|Show|Enum|Eq|Ord|Data|Bounded|Typeable|Num|Real|Fractional|Integral|RealFrac|Floating|RealFloat|Monad|MonadPlus|Functor)"
|
- identifier.class: "\\b(Read|Show|Enum|Eq|Ord|Data|Bounded|Typeable|Num|Real|Fractional|Integral|RealFrac|Floating|RealFloat|Monad|MonadPlus|Functor|Foldable|Additive|Zip)[ ]"
|
||||||
|
|
||||||
# Strings
|
# Strings
|
||||||
- constant.string:
|
- constant.string:
|
||||||
|
|||||||
@@ -4,44 +4,67 @@ detect:
|
|||||||
filename: "\\.htm[l]?$"
|
filename: "\\.htm[l]?$"
|
||||||
|
|
||||||
rules:
|
rules:
|
||||||
- error: "<[^!].*?>"
|
# Doctype is case-insensitive
|
||||||
- symbol.tag: "(?i)<[/]?(a(bbr|cronym|ddress|pplet|rea|rticle|side|udio)?|b(ase(font)?|d(i|o)|ig|lockquote|r)?|ca(nvas|ption)|center|cite|co(de|l|lgroup)|d(ata(list)?|d|el|etails|fn|ialog|ir|l|t)|em(bed)?|fieldset|fig(caption|ure)|font|form|(i)?frame|frameset|h[1-6]|hr|i|img|in(put|s)|kbd|keygen|label|legend|li(nk)?|ma(in|p|rk)|menu(item)?|met(a|er)|nav|no(frames|script)|o(l|pt(group|ion)|utput)|p(aram|icture|re|rogress)?|q|r(p|t|uby)|s(trike)?|samp|se(ction|lect)|small|source|span|strong|su(b|p|mmary)|textarea|time|track|u(l)?|var|video|wbr)( .*|>)*?>"
|
- preproc: "<!(?i)(DOCTYPE html.*)>"
|
||||||
- symbol.tag.extended: "(?i)<[/]?(body|div|html|head(er)?|footer|title|table|t(body|d|h(ead)?|r|foot))( .*)*?>"
|
# Opening tag
|
||||||
- special: "&(#[[:digit:]]{1,4}|#x[[:xdigit:]]{1,4}|[^[[:space:]]]+);"
|
- symbol.tag:
|
||||||
- symbol: "[:=]"
|
start: "<(a|abbr|acronym|address|applet|area|article|aside|audio|b|base|bdi|bdo|big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|dir|div|dl|dt|em|embed|fieldset|figcaption|figure|font|footer|form|frame|frameset|h[1-6]|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|s|samp|section|select|small|source|span|strike|strong|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|track|tt|u|ul|var|video|wbr)\\b"
|
||||||
- identifier: "(alt|bgcolor|height|href|id|label|longdesc|name|on(click|focus|load|mouseover)|size|span|src|target|type|value|width)="
|
end: ">"
|
||||||
- constant.number: "(?i)#[0-9A-F]{6,6}"
|
|
||||||
# - default:
|
|
||||||
# start: ">"
|
|
||||||
# end: "<"
|
|
||||||
# rules: []
|
|
||||||
|
|
||||||
- symbol.tag: "<|>"
|
|
||||||
- constant.string.url: "(ftp(s)?|http(s)?|git|chrome)://[^ ]+"
|
|
||||||
- preproc: "<!DOCTYPE.+?>"
|
|
||||||
|
|
||||||
- comment:
|
|
||||||
start: "<!--"
|
|
||||||
end: "-->"
|
|
||||||
rules: []
|
|
||||||
|
|
||||||
- constant.string:
|
|
||||||
start: "\""
|
|
||||||
end: "\""
|
|
||||||
skip: "\\\\."
|
|
||||||
rules:
|
rules:
|
||||||
- constant.specialChar: "\\\\."
|
- identifier: "\\b(placeholder|style|alt|bgcolor|height|href|id|(aria|data)\\-.+|label|longdesc|name|on(click|focus|load|mouseover)|size|span|src|target|type|value|width|class|charset|content|rel|integrity|crossorigin|for|onsubmit|lang|role)\\b"
|
||||||
|
- special: "\\b(required)\\b"
|
||||||
|
# Match double-quote strings
|
||||||
|
- constant.string:
|
||||||
|
start: "\""
|
||||||
|
end: "\""
|
||||||
|
skip: "\\\\."
|
||||||
|
rules:
|
||||||
|
- constant.specialChar: "\\\\."
|
||||||
|
- constant.string.url: "((ftp(s)?|http(s)?|git|chrome)://[^\\s]+)"
|
||||||
|
# Match single-quote strings
|
||||||
|
- constant.string:
|
||||||
|
start: "'"
|
||||||
|
end: "'"
|
||||||
|
skip: "\\\\."
|
||||||
|
rules:
|
||||||
|
- constant.specialChar: "\\\\."
|
||||||
|
- constant.string.url: "((ftp(s)?|http(s)?|git|chrome)://[^\\s]+)"
|
||||||
|
# Highlight the equals and any colon between words
|
||||||
|
- symbol: "\\b(=|:\\b)"
|
||||||
|
|
||||||
|
# Closing tag
|
||||||
|
- symbol.tag:
|
||||||
|
start: "</(a|abbr|acronym|address|applet|area|article|aside|audio|b|base|bdi|bdo|big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|dir|div|dl|dt|em|embed|fieldset|figcaption|figure|font|footer|form|frame|frameset|h[1-6]|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|s|samp|section|select|small|source|span|strike|strong|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|track|tt|u|ul|var|video|wbr)\\b"
|
||||||
|
end: ">"
|
||||||
|
rules:
|
||||||
|
# Anything in the closing tag is an error
|
||||||
|
- error: "."
|
||||||
|
|
||||||
|
# Reserved entities like a and Ī
|
||||||
|
- special: "(([a-zA-Z]&#[0-9]+|&[a-zA-Z]+|&#[a-zA-Z0-9]+);)"
|
||||||
|
|
||||||
|
# TODO: Add `limit-rules` to both the `default` rules below once it's implemented into Micro
|
||||||
- default:
|
- default:
|
||||||
start: "<script.*?>"
|
start: "<script.*?>"
|
||||||
end: "</script.*?>"
|
end: "</script.*?>"
|
||||||
limit-group: symbol.tag
|
limit-group: symbol.tag
|
||||||
rules:
|
rules:
|
||||||
- include: "javascript"
|
- include: "javascript"
|
||||||
|
|
||||||
- default:
|
- default:
|
||||||
start: "<style.*?>"
|
start: "<style.*?>"
|
||||||
end: "</style.*?>"
|
end: "</style.*?>"
|
||||||
limit-group: symbol.tag
|
limit-group: symbol.tag
|
||||||
rules:
|
rules:
|
||||||
- include: "css"
|
- include: "css"
|
||||||
|
|
||||||
|
# This weird empty comment thing is technically valid
|
||||||
|
- comment: "<!>"
|
||||||
|
|
||||||
|
- comment.block:
|
||||||
|
start: "<!\\-\\-"
|
||||||
|
end: "\\-\\->"
|
||||||
|
rules:
|
||||||
|
- todo: "(FIXME|NOTE|TODO):?"
|
||||||
|
# While technically not a "true" error, these are recommended to not be used inside a comment
|
||||||
|
- error: "(\\-\\-|>)"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
filetype: v
|
filetype: v
|
||||||
|
|
||||||
detect:
|
detect:
|
||||||
filename: "\\.v$"
|
|
||||||
|
|
||||||
rules:
|
rules:
|
||||||
# Conditionals and control flow
|
# Conditionals and control flow
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
filetype: verilog
|
filetype: verilog
|
||||||
|
|
||||||
detect:
|
detect:
|
||||||
filename: "\\.(vh|sv|svh)$"
|
filename: "\\.(v|vh|sv|svh)$"
|
||||||
|
|
||||||
rules:
|
rules:
|
||||||
- preproc: "\\b(module|package|program|endmodule|endpackage|endprogram)\\b"
|
- preproc: "\\b(module|package|program|endmodule|endpackage|endprogram)\\b"
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
name: micro
|
name: micro
|
||||||
version: git
|
|
||||||
summary: A modern and intuitive terminal-based text editor
|
summary: A modern and intuitive terminal-based text editor
|
||||||
description: |
|
description: |
|
||||||
Micro is a terminal-based text editor that aims to be easy to use and
|
Micro is a terminal-based text editor that aims to be easy to use and
|
||||||
intuitive, while also taking advantage of the full capabilities of modern
|
intuitive, while also taking advantage of the full capabilities of modern
|
||||||
terminals.
|
terminals.
|
||||||
confinement: classic
|
confinement: classic
|
||||||
|
adopt-info: micro
|
||||||
|
|
||||||
apps:
|
apps:
|
||||||
micro:
|
micro:
|
||||||
@@ -19,7 +19,13 @@ parts:
|
|||||||
build-packages: [make]
|
build-packages: [make]
|
||||||
build-snaps: [go]
|
build-snaps: [go]
|
||||||
build-attributes: [no-patchelf]
|
build-attributes: [no-patchelf]
|
||||||
|
override-pull: |
|
||||||
|
snapcraftctl pull
|
||||||
|
version="$(go run $SNAPCRAFT_PART_SRC/tools/build-version.go)"
|
||||||
|
[ -n "$(echo $version | grep "dev")" ] && grade=devel || grade=stable
|
||||||
|
snapcraftctl set-version "$version"
|
||||||
|
snapcraftctl set-grade "$grade"
|
||||||
override-build: |
|
override-build: |
|
||||||
make build
|
make build-tags
|
||||||
mkdir $SNAPCRAFT_PART_INSTALL/bin
|
mkdir $SNAPCRAFT_PART_INSTALL/bin
|
||||||
mv ./micro $SNAPCRAFT_PART_INSTALL/bin/
|
mv ./micro $SNAPCRAFT_PART_INSTALL/bin/
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ func getTag(match ...string) (string, *semver.PRVersion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
if tags, err := exec.Command("git", "tag").Output(); err != nil || len(tags) == 0 {
|
||||||
|
// no tags found -- fetch them
|
||||||
|
exec.Command("git", "fetch", "--tags").Run()
|
||||||
|
}
|
||||||
// Find the last vX.X.X Tag and get how many builds we are ahead of it.
|
// Find the last vX.X.X Tag and get how many builds we are ahead of it.
|
||||||
versionStr, ahead := getTag("--match", "v*")
|
versionStr, ahead := getTag("--match", "v*")
|
||||||
version, err := semver.ParseTolerant(versionStr)
|
version, err := semver.ParseTolerant(versionStr)
|
||||||
@@ -49,7 +53,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we don't have any tag assume "dev"
|
// If we don't have any tag assume "dev"
|
||||||
if tag == "" {
|
if tag == "" || strings.HasPrefix(tag, "nightly") {
|
||||||
tag = "dev"
|
tag = "dev"
|
||||||
}
|
}
|
||||||
// Get the most likely next version:
|
// Get the most likely next version:
|
||||||
|
|||||||
267
tools/testgen.go
Normal file
267
tools/testgen.go
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/robertkrimen/otto/ast"
|
||||||
|
"github.com/robertkrimen/otto/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
type walker struct {
|
||||||
|
nodes []ast.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *walker) Enter(node ast.Node) ast.Visitor {
|
||||||
|
w.nodes = append(w.nodes, node)
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *walker) Exit(node ast.Node) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAllNodes(node ast.Node) []ast.Node {
|
||||||
|
w := &walker{}
|
||||||
|
ast.Walk(w, node)
|
||||||
|
return w.nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCalls(node ast.Node, name string) []*ast.CallExpression {
|
||||||
|
nodes := []*ast.CallExpression{}
|
||||||
|
for _, n := range getAllNodes(node) {
|
||||||
|
if ce, ok := n.(*ast.CallExpression); ok {
|
||||||
|
var calleeName string
|
||||||
|
switch callee := ce.Callee.(type) {
|
||||||
|
case *ast.Identifier:
|
||||||
|
calleeName = callee.Name
|
||||||
|
case *ast.DotExpression:
|
||||||
|
calleeName = callee.Identifier.Name
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if calleeName == name {
|
||||||
|
nodes = append(nodes, ce)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPropertyValue(node ast.Node, key string) ast.Expression {
|
||||||
|
for _, p := range node.(*ast.ObjectLiteral).Value {
|
||||||
|
if p.Key == key {
|
||||||
|
return p.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type operation struct {
|
||||||
|
startLine int
|
||||||
|
startColumn int
|
||||||
|
endLine int
|
||||||
|
endColumn int
|
||||||
|
text []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type check struct {
|
||||||
|
before []string
|
||||||
|
operations []operation
|
||||||
|
after []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type test struct {
|
||||||
|
description string
|
||||||
|
checks []check
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringSliceToGoSource(slice []string) string {
|
||||||
|
var b strings.Builder
|
||||||
|
b.WriteString("[]string{\n")
|
||||||
|
for _, s := range slice {
|
||||||
|
b.WriteString(fmt.Sprintf("%#v,\n", s))
|
||||||
|
}
|
||||||
|
b.WriteString("}")
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testToGoTest(test test, name string) string {
|
||||||
|
var b strings.Builder
|
||||||
|
|
||||||
|
b.WriteString("func Test")
|
||||||
|
b.WriteString(name)
|
||||||
|
b.WriteString("(t *testing.T) {\n")
|
||||||
|
|
||||||
|
for _, c := range test.checks {
|
||||||
|
b.WriteString("check(\n")
|
||||||
|
b.WriteString("t,\n")
|
||||||
|
b.WriteString(fmt.Sprintf("%v,\n", stringSliceToGoSource(c.before)))
|
||||||
|
b.WriteString("[]operation{\n")
|
||||||
|
for _, op := range c.operations {
|
||||||
|
b.WriteString("operation{\n")
|
||||||
|
b.WriteString(fmt.Sprintf("start: Loc{%v, %v},\n", op.startColumn, op.startLine))
|
||||||
|
b.WriteString(fmt.Sprintf("end: Loc{%v, %v},\n", op.endColumn, op.endLine))
|
||||||
|
b.WriteString(fmt.Sprintf("text: %v,\n", stringSliceToGoSource(op.text)))
|
||||||
|
b.WriteString("},\n")
|
||||||
|
}
|
||||||
|
b.WriteString("},\n")
|
||||||
|
b.WriteString(fmt.Sprintf("%v,\n", stringSliceToGoSource(c.after)))
|
||||||
|
b.WriteString(")\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteString("}\n")
|
||||||
|
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func nodeToStringSlice(node ast.Node) []string {
|
||||||
|
var result []string
|
||||||
|
for _, s := range node.(*ast.ArrayLiteral).Value {
|
||||||
|
result = append(result, s.(*ast.StringLiteral).Value)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func nodeToStringSlice2(node ast.Node) []string {
|
||||||
|
var result []string
|
||||||
|
for _, o := range node.(*ast.ArrayLiteral).Value {
|
||||||
|
result = append(result, getPropertyValue(o, "text").(*ast.StringLiteral).Value)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func nodeToInt(node ast.Node) int {
|
||||||
|
return int(node.(*ast.NumberLiteral).Value.(int64))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getChecks(node ast.Node) []check {
|
||||||
|
checks := []check{}
|
||||||
|
|
||||||
|
for _, ce := range getCalls(node, "testApplyEdits") {
|
||||||
|
if len(ce.ArgumentList) != 3 {
|
||||||
|
// Wrong function
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
before := nodeToStringSlice2(ce.ArgumentList[0])
|
||||||
|
after := nodeToStringSlice2(ce.ArgumentList[2])
|
||||||
|
|
||||||
|
var operations []operation
|
||||||
|
for _, op := range ce.ArgumentList[1].(*ast.ArrayLiteral).Value {
|
||||||
|
args := getPropertyValue(op, "range").(*ast.NewExpression).ArgumentList
|
||||||
|
operations = append(operations, operation{
|
||||||
|
startLine: nodeToInt(args[0]) - 1,
|
||||||
|
startColumn: nodeToInt(args[1]) - 1,
|
||||||
|
endLine: nodeToInt(args[2]) - 1,
|
||||||
|
endColumn: nodeToInt(args[3]) - 1,
|
||||||
|
text: []string{getPropertyValue(op, "text").(*ast.StringLiteral).Value},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
checks = append(checks, check{before, operations, after})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ce := range getCalls(node, "testApplyEditsWithSyncedModels") {
|
||||||
|
if len(ce.ArgumentList) > 3 && ce.ArgumentList[3].(*ast.BooleanLiteral).Value {
|
||||||
|
// inputEditsAreInvalid == true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
before := nodeToStringSlice(ce.ArgumentList[0])
|
||||||
|
after := nodeToStringSlice(ce.ArgumentList[2])
|
||||||
|
|
||||||
|
var operations []operation
|
||||||
|
for _, op := range getCalls(ce.ArgumentList[1], "editOp") {
|
||||||
|
operations = append(operations, operation{
|
||||||
|
startLine: nodeToInt(op.ArgumentList[0]) - 1,
|
||||||
|
startColumn: nodeToInt(op.ArgumentList[1]) - 1,
|
||||||
|
endLine: nodeToInt(op.ArgumentList[2]) - 1,
|
||||||
|
endColumn: nodeToInt(op.ArgumentList[3]) - 1,
|
||||||
|
text: nodeToStringSlice(op.ArgumentList[4]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
checks = append(checks, check{before, operations, after})
|
||||||
|
}
|
||||||
|
|
||||||
|
return checks
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTests(node ast.Node) []test {
|
||||||
|
tests := []test{}
|
||||||
|
for _, ce := range getCalls(node, "test") {
|
||||||
|
description := ce.ArgumentList[0].(*ast.StringLiteral).Value
|
||||||
|
body := ce.ArgumentList[1].(*ast.FunctionLiteral).Body
|
||||||
|
checks := getChecks(body)
|
||||||
|
if len(checks) > 0 {
|
||||||
|
tests = append(tests, test{description, checks})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tests
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var tests []test
|
||||||
|
|
||||||
|
for _, filename := range os.Args[1:] {
|
||||||
|
source, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
program, err := parser.ParseFile(nil, "", source, parser.IgnoreRegExpErrors)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tests = append(tests, getTests(program)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tests) == 0 {
|
||||||
|
log.Fatalln("no tests found!")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("// This file is generated from VSCode model tests by the testgen tool.")
|
||||||
|
fmt.Println("// DO NOT EDIT THIS FILE BY HAND; your changes will be overwritten!\n")
|
||||||
|
fmt.Println("package buffer")
|
||||||
|
fmt.Println(`import "testing"`)
|
||||||
|
|
||||||
|
re := regexp.MustCompile(`[^\w]`)
|
||||||
|
usedNames := map[string]bool{}
|
||||||
|
|
||||||
|
var b strings.Builder
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
name := strings.Title(strings.ToLower(test.description))
|
||||||
|
name = re.ReplaceAllLiteralString(name, "")
|
||||||
|
if name == "" {
|
||||||
|
name = "Unnamed"
|
||||||
|
}
|
||||||
|
if usedNames[name] {
|
||||||
|
for i := 2; ; i++ {
|
||||||
|
newName := fmt.Sprintf("%v_%v", name, i)
|
||||||
|
if !usedNames[newName] {
|
||||||
|
name = newName
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usedNames[name] = true
|
||||||
|
|
||||||
|
fmt.Println(testToGoTest(test, name))
|
||||||
|
|
||||||
|
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