Compare commits

..

125 Commits

Author SHA1 Message Date
Zachary Yedidia
5e82fc4673 Update readme 2016-09-06 20:33:39 -04:00
Zachary Yedidia
107a6f877b Update readme 2016-09-06 20:32:21 -04:00
Zachary Yedidia
e643860e3d Add Open command for view 2016-09-06 19:58:34 -04:00
Zachary Yedidia
0373589ab8 Merge 2016-09-06 19:30:28 -04:00
Zachary Yedidia
dce56a2b85 Have HandleShellCommand return the stdout
HandleShellCommand will now return the stdout as a string and
it also takes an additional flag indicating whether it should
wait before closing the shell and returning to the editor.
2016-09-06 19:27:57 -04:00
Zachary Yedidia
27d2ebfb45 Merge pull request #325 from techtonik/patch-1
Fix CanClose comment after API change
2016-09-06 16:02:45 -04:00
anatoly techtonik
1f457f9d9e Fix CanClose comment after API change
Follow up to 966dac97f8
2016-09-06 22:51:13 +03:00
Zachary Yedidia
c0282c4a3c Add issue template 2016-09-06 11:24:55 -04:00
Zachary Yedidia
0a6e1de404 Merge branch 'boombuler-params' 2016-09-06 10:59:46 -04:00
Zachary Yedidia
131524e670 Merge branch 'params' of https://github.com/boombuler/micro into boombuler-params 2016-09-06 10:59:30 -04:00
Zachary Yedidia
539495d2f7 Add support for macros
Closes #270

CtrlU to toggle recording and CtrlJ to playback.
You can also rebind using the "ToggleMacro" and "PlayMacro"
actions.

Note that recursive macros are not yet supported.
2016-09-06 10:44:15 -04:00
Zachary Yedidia
966dac97f8 Make unsaved changes prompt more clear
Fixes #301
2016-09-06 10:06:36 -04:00
Zachary Yedidia
bf6e596808 Merge pull request #323 from zonuexe/php-keywords
Add PHP Keywords
2016-09-06 07:24:22 -04:00
USAMI Kenta
efa24f5a8d Add PHP Keywords
- trait (PHP 5.5)
- iterable (PHP 7.1)
- void (PHP 7.1)

see https://github.com/ejmr/php-mode/pull/317
2016-09-06 18:25:08 +09:00
Zachary Yedidia
432146b068 Merge pull request #318 from elopio/update_runtime
Update runtime
2016-09-05 16:12:26 -04:00
Leo Arias
02b6eaaff0 Update runtime
closes #317
2016-09-05 18:31:36 +00:00
Zachary Yedidia
dc532e337b Merge pull request #315 from boombuler/pascal
added pascal syntax
2016-09-05 12:10:56 -04:00
boombuler
a952e249b4 added pascal syntax 2016-09-05 17:53:49 +02:00
Zachary Yedidia
94465ef1ae Merge 2016-09-05 11:38:16 -04:00
Zachary Yedidia
0a534767f0 Merge branch 'primary-clipboard' 2016-09-05 11:37:49 -04:00
Zachary Yedidia
7937f7038b Merge pull request #314 from mame98/master
Added some SCSS keywords for the css/scss highlighting
2016-09-05 10:50:00 -04:00
Marius Messerschmidt
d6a01ad29f Added some SCSS keywords for the css/scss highlighting
Signed-off-by: Marius Messerschmidt <marius.messerschmidt@googlemail.com>
2016-09-05 16:41:32 +02:00
Zachary Yedidia
b1cb583e8c Update runtime 2016-09-05 10:30:08 -04:00
Zachary Yedidia
ea4d822923 Merge pull request #283 from boombuler/autocompleteplugin
Autocomplete for plugins
2016-09-05 10:29:51 -04:00
Zachary Yedidia
583177feff Update readme 2016-09-05 10:29:15 -04:00
Zachary Yedidia
3bec1b8c1b Merge pull request #313 from adrianvoica/master
Updates to TypeScript dictionary.
2016-09-05 10:28:36 -04:00
Adrian Voica
b992669f5b Updates to TypeScript dictionary. 2016-09-05 17:18:41 +03:00
Zachary Yedidia
086aa61e5a Merge pull request #311 from adrianvoica/master
Added TypeScript syntax highlighting file.
2016-09-05 10:09:23 -04:00
Adrian Voica
c310053777 Added TypeScript syntax highlighting file. 2016-09-05 17:01:37 +03:00
Zachary Yedidia
2041e12eba Fix some issues with mouse selection copying 2016-09-05 08:36:30 -04:00
Zachary Yedidia
5d00522d4e Deselect for CursorStart
Fixes #308
2016-09-05 08:25:49 -04:00
Zachary Yedidia
c71e816e37 Fix recursive function 2016-09-04 21:28:40 -04:00
Zachary Yedidia
6721ec8e7d Copy to primary clipboard for any change in selection 2016-09-04 21:19:14 -04:00
Zachary Yedidia
93eadfb9dc Merge 2016-09-04 18:27:16 -04:00
Zachary Yedidia
cf3ce29a08 Fix YesNoPrompt bug 2016-09-04 18:27:11 -04:00
Zachary Yedidia
cd1117c08c Merge pull request #304 from techtonik/windate
Windows-compatible Makefile
2016-09-04 15:17:27 -04:00
anatoly techtonik
f247823936 Get build date on Windows without Python 2016-09-04 22:07:07 +03:00
Zachary Yedidia
a8feef3c12 Minor cleanup
See #300
2016-09-04 12:57:09 -04:00
Zachary Yedidia
de9707f088 Merge 2016-09-04 12:51:00 -04:00
Zachary Yedidia
9ff396c69f Don't allow setting invalid colorschemes
Fixes #303
2016-09-04 12:50:13 -04:00
anatoly techtonik
4b350d02e0 Let Go choose binary name and extension
This creates micro.exe on Windows
2016-09-04 19:38:50 +03:00
anatoly techtonik
ae3696e82d Use Python to get date in cross-platform way
I was able to build micro with Mozilla's pymake on Windows
2016-09-04 19:31:16 +03:00
Zachary Yedidia
b3f6731db5 Update runtime 2016-09-04 11:36:25 -04:00
Zachary Yedidia
2b9ef4d406 Merge 2016-09-04 11:20:18 -04:00
Zachary Yedidia
54a34001e3 Fix cursor problem in LetterPrompt
Fixes #300
2016-09-04 11:19:53 -04:00
Zachary Yedidia
aad7cc7572 Merge pull request #299 from skovsgaard/add-lfe
Add an LFE syntax file
2016-09-04 11:02:41 -04:00
Zachary Yedidia
def5e29b91 Merge pull request #302 from tanuck/align-tabs-with-spaces
Correct the number of spaces in a tab
2016-09-04 10:58:12 -04:00
James Tancock
187ea0da1c Correct the number of spaces to add when a tab is inserted at an offset cursor.
Fixes #268
2016-09-04 15:50:39 +01:00
Zachary Yedidia
5b7fa01825 Add newline to end of settings.json
Fixes #296
2016-09-04 10:10:57 -04:00
Zachary Yedidia
c38044106c Merge pull request #298 from boombuler/bug269
exit conditional replace if no match is left
2016-09-04 09:44:05 -04:00
skovsgaard
399e3a5ee1 Add an LFE syntax file 2016-09-04 11:11:30 +02:00
boombuler
fce5b81c22 exit conditional replace if no match is left 2016-09-04 09:29:26 +02:00
Zachary Yedidia
a4ac9f2b7b Merge pull request #286 from boombuler/bug269
fixes conditional replace
2016-09-03 13:45:43 -04:00
Zachary Yedidia
abedeebc0a Merge pull request #282 from boombuler/windows
File autocomplete should now work on windows
2016-09-03 13:45:19 -04:00
Zachary Yedidia
b905400892 Add default bindings for CtrlHome and CtrlEnd
Fixes #280
2016-09-03 13:37:16 -04:00
Zachary Yedidia
c4d6f5e584 Fix various infobar bugs
Fixes #294
Fixes #295
2016-09-03 13:28:48 -04:00
Zachary Yedidia
b5232dd24d Merge 2016-09-03 13:00:23 -04:00
Zachary Yedidia
89886f10c7 Update conf.micro syntax file
Fixes #290
2016-09-03 13:00:05 -04:00
Zachary Yedidia
c679500d06 Merge pull request #292 from devoncarew/fix_typo
fix a typo
2016-09-03 12:53:47 -04:00
Zachary Yedidia
76f80bf694 Merge pull request #293 from devoncarew/add_dart
add dart syntax highlighting
2016-09-03 12:53:39 -04:00
Devon Carew
a7b72f0e0e add dart syntax highlighting 2016-09-03 09:16:52 -07:00
Devon Carew
00eb6725e6 fix a typo 2016-09-03 09:16:08 -07:00
Zachary Yedidia
af22e0a567 Allow overwriting options with flags
Fixes #258

Also related to #233, this commit also changes how +LINE,COL works. Now it is
micro -startpos LINE,COL file.
2016-09-03 11:26:01 -04:00
boombuler
98b6f63b70 fixes conditional replace
before this, conditional replace always replaces the first found
occurence of the match not the currenly selected.
Might also fix #269
2016-09-03 12:34:57 +02:00
boombuler
403a99d2ea removed obsolete replace command preparations 2016-09-03 12:13:25 +02:00
boombuler
b2735d7b5b use build-in functions to quote / unquote 2016-09-03 12:02:49 +02:00
boombuler
699ad316e5 removed old code 2016-09-03 08:18:47 +02:00
boombuler
8617ae5c1f keep trailing space at commandline 2016-09-03 08:16:18 +02:00
boombuler
c5ac5be764 updated plugin help 2016-09-02 19:50:19 +02:00
boombuler
881f57b047 allow plugins to register autocomplete functions 2016-09-02 19:42:33 +02:00
Zachary Yedidia
1c2b815d95 Merge 2016-09-02 11:12:36 -04:00
Zachary Yedidia
b45fcf5bd7 Use json5 for config files 2016-09-02 11:12:16 -04:00
Zachary Yedidia
45ec01d197 Merge pull request #281 from onodera-punpun/patch-1
sh.micro: Add some linux config files that use sh.
2016-09-02 10:53:55 -04:00
Camille
0df7e59ca4 sh.micro: Add some linux config files that use sh. 2016-09-02 16:49:19 +02:00
Zachary Yedidia
89c34ed8b3 Copy to primary clipboard on mouse selection 2016-09-02 10:44:32 -04:00
Zachary Yedidia
d9b8a04841 Add support for primary clipboard 2016-09-02 09:40:08 -04:00
Florian Sundermann
ccfe08bc60 allow command parameters to be quoted
this way FileCompletions could contain space runes without
breaking the parameter.
2016-09-02 13:44:22 +02:00
Florian Sundermann
2e3ee22aca File autocomplete should now work on windows 2016-09-02 08:49:54 +02:00
Zachary Yedidia
226cf399ba Merge pull request #271 from teryanik/master
Improvement highlight php syntax
2016-09-01 20:23:53 -04:00
Zachary Yedidia
0f6260601f Merge pull request #272 from thecotne/master
improve json.micro
2016-09-01 20:23:38 -04:00
cotne nazarashvili
d2254df062 improve json.micro 2016-09-02 03:59:36 +04:00
teryanik
3e83d29fb4 improvement highlight php syntax 2016-09-01 22:24:31 +03:00
Zachary Yedidia
a432bc7e7b Fix typo in readme 2016-09-01 12:09:49 -04:00
Zachary Yedidia
486279e1d1 Update readme 2016-09-01 12:08:46 -04:00
Zachary Yedidia
3967981b38 Fix help links in readme 2016-08-31 20:05:35 -04:00
Zachary Yedidia
597c549b5b Update readme 2016-08-31 20:04:24 -04:00
Zachary Yedidia
fc2d9bb461 Merge pull request #233 from schollz/master
Flag to start at specified line/column number (#224)
2016-08-31 16:39:30 -04:00
Zachary Yedidia
832cc366af Merge 2016-08-31 14:22:19 -04:00
Zachary Yedidia
5458605618 Add "bubblegum" light colorscheme
Closes #255
2016-08-31 14:21:46 -04:00
Zachary Yedidia
104af2ef7a Merge pull request #263 from dtakahas/fix-help-typos
Fix a couple typos in help files
2016-08-31 14:08:38 -04:00
Dave Takahashi
64ff933451 Fix a couple typos in help files 2016-08-31 11:01:30 -07:00
Zachary Yedidia
031ed64305 Add colorscheme support for gentoo-ebuild
See #229
2016-08-31 12:12:23 -04:00
Zachary Yedidia
1be332a0f9 Merge 2016-08-31 12:00:28 -04:00
Zachary Yedidia
b9d4dbd5e0 Add colorscheme support for yaml
See #229
2016-08-31 11:59:43 -04:00
Zachary Yedidia
2e264b342a Fix prompts not displaying because of infobar 2016-08-31 11:52:59 -04:00
Zachary Yedidia
4972db4bf6 Merge 2016-08-31 11:16:58 -04:00
Zachary Yedidia
b70db77c29 Add infobar option to disable the message line
Fixes #257
2016-08-31 11:16:22 -04:00
Zachary Yedidia
f8612d1572 Merge pull request #259 from handicraftsman/master
ASM & Micro fix
2016-08-31 10:53:14 -04:00
Nickolay
f9d0c563e4 Fixed Micro & ASM syntax files 2016-08-31 17:50:09 +03:00
Zachary Yedidia
3105205ab8 Use text from the paste event, not the clipboard
Closes #93
2016-08-31 10:47:31 -04:00
Nickolay
ec29d592da Merge pull request #1 from zyedidia/master
Sync repos for updating ASM syntax
2016-08-31 17:41:53 +03:00
Zack Scholl
62ac9f79f2 Switched to +LINE,COL
Previously the flag was parsed for `-cursor LINE,COL`

However, emacs and nano both us `+LINE,COL` and this also makes
it easier to ignore the `+` as a filename.
2016-08-31 10:10:54 -04:00
Zachary Yedidia
a6d695f471 Merge 2016-08-31 08:51:44 -04:00
Zachary Yedidia
59d2fa81dd Unselect for cursor movement actions
Fixes #250
2016-08-31 08:51:24 -04:00
Zachary Yedidia
4003586456 Merge pull request #253 from xDShot/patch-1
Update ini.micro
2016-08-31 08:36:54 -04:00
Zachary Yedidia
be44dc3ff5 Merge pull request #256 from handicraftsman/master
Added .micro syntax theme
2016-08-31 08:36:31 -04:00
Nickolay
c59b1ea387 Added .micro syntax theme 2016-08-31 15:19:45 +03:00
xDShot
00089a7c01 Update ini.micro 2016-08-31 12:06:46 +03:00
Zachary Yedidia
c661c65c8c Update help to give quick instructions on quitting and saving 2016-08-30 21:29:41 -04:00
Zachary Yedidia
13da5ced15 Fix problem with linter.onSave calling view.Save
Fixes #246
2016-08-30 19:38:45 -04:00
Zachary Yedidia
b970b393f2 Add caddyfile to runtime 2016-08-30 19:32:26 -04:00
Zachary Yedidia
30323116a5 Merge pull request #247 from mholt/patch-1
Add Caddyfile syntax
2016-08-30 19:30:46 -04:00
Matt Holt
2fc274da7d Add Caddyfile syntax 2016-08-30 17:22:55 -06:00
Zachary Yedidia
b19b36d113 Update syntax file readme
Fixes #245
2016-08-30 18:08:26 -04:00
Zachary Yedidia
b6f5db3692 Add QuitAll action to close all splits and tabs at once
See #239
2016-08-30 17:38:46 -04:00
Zachary Yedidia
8bdaacaa5e Switch splits on mouse *click* not drag
Fixes #240
2016-08-30 17:29:49 -04:00
Zachary Yedidia
c9ead25b1e Merge 2016-08-30 17:26:05 -04:00
Zachary Yedidia
ddff950fcd Check for filetype after saving an untitled buffer
Fixes #242
2016-08-30 17:25:30 -04:00
Zachary Yedidia
ed6be89d5c Merge pull request #241 from handicraftsman/master
ASM Support
2016-08-30 17:21:14 -04:00
Nickolay
6e63472930 Whooops! 2016-08-31 00:08:37 +03:00
Nickolay
94397a90bd Fully finished ASM syntax highlightig 2016-08-31 00:03:22 +03:00
Nickolay
216bfaca7e Added SIMD, Crypto and undocumented instructions 2016-08-30 23:02:03 +03:00
Nickolay
9854fc712f Added x87 instructions 2016-08-30 22:13:46 +03:00
Nickolay
99635d9491 Added x86 cpu support for assembly. 2016-08-30 21:51:30 +03:00
Zack Scholl
4499228cdb Added flag to introduce cursor starting positions 2016-08-30 11:28:28 -04:00
47 changed files with 1244 additions and 310 deletions

9
.github/ISSUE_TEMPLATE vendored Normal file
View File

@@ -0,0 +1,9 @@
## Description of the problem or steps to reproduce
## Specifications
You can use `micro -version` to get the commit hash.
Commit hash:
OS:
Terminal:

2
.gitignore vendored
View File

@@ -1,3 +1,5 @@
./micro
!cmd/micro
binaries/
tmp.sh
test/

View File

@@ -2,17 +2,18 @@
VERSION = $(shell git describe --tags --abbrev=0)
HASH = $(shell git rev-parse --short HEAD)
DATE = $(shell go run tools/build-date.go)
# Builds micro after checking dependencies but without updating the runtime
build: deps tcell
go build -ldflags "-X main.Version=$(VERSION) -X main.CommitHash=$(HASH) -X 'main.CompileDate=$(shell date -u '+%B %d, %Y')'" -o micro ./cmd/micro
go build -ldflags "-X main.Version=$(VERSION) -X main.CommitHash=$(HASH) -X 'main.CompileDate=$(DATE)'" ./cmd/micro
# Builds micro after building the runtiem and checking dependencies
# Builds micro after building the runtime and checking dependencies
build-all: runtime build
# Builds micro without checking for dependencies
build-quick:
go build -ldflags "-X main.Version=$(VERSION) -X main.CommitHash=$(HASH) -X 'main.CompileDate=$(shell date -u '+%B %d, %Y')'" -o micro ./cmd/micro
go build -ldflags "-X main.Version=$(VERSION) -X main.CommitHash=$(HASH) -X 'main.CompileDate=$(DATE)'" ./cmd/micro
# Same as 'build' but installs to $GOPATH/bin afterward
install: build

View File

@@ -40,9 +40,10 @@ To see more screenshots of micro, showcasing all of the default colorschemes, se
* Copy and paste with the system clipboard
* Small and simple
* Easily configurable
* Macros
* Common editor things such as undo/redo, line numbers, unicode support...
Although not yet implemented, I hope to add more features such as autocompletion, and multiple cursors in the future.
Although not yet implemented, I hope to add more features such as autocompletion ([#174](https://github.com/zyedidia/micro/issues/174)), and multiple cursors ([#5](https://github.com/zyedidia/micro/issues/5)) in the future.
# Installation
@@ -61,6 +62,15 @@ 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`.
### Homebrew
You can also install micro using Homebrew:
```
$ brew tap zyedidia/micro
$ brew install micro
```
### Building from source
If your operating system does not have binary, but does run Go, you can build from source.
@@ -122,7 +132,14 @@ click to enable line selection.
# Documentation and Help
Micro has a built-in help system which you can access by pressing `CtrlE` and typing `help`. Additionally, you can
view the help files online [here](https://github.com/zyedidia/micro/tree/master/runtime/help).
view the help files here:
* [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)
* [commands](https://github.com/zyedidia/micro/tree/master/runtime/help/commands.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)
* [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
a brief introduction to the more powerful configuration features micro offers.
@@ -132,3 +149,5 @@ a brief introduction to the more powerful configuration features micro offers.
If you find any bugs, please report them! I am also happy to accept pull requests from anyone.
You can use the Github issue tracker to report bugs, ask questions, or suggest new features.
For a more informal setting to discuss the editor, you can join the [Gitter chat](https://gitter.im/zyedidia/micro).

View File

@@ -1,13 +1,11 @@
package main
import (
"io/ioutil"
"os"
"strconv"
"strings"
"time"
"github.com/mitchellh/go-homedir"
"github.com/yuin/gopher-lua"
"github.com/zyedidia/clipboard"
)
@@ -44,6 +42,15 @@ func PostActionCall(funcName string, view *View) bool {
return relocate
}
func (v *View) deselect(index int) bool {
if v.Cursor.HasSelection() {
v.Cursor.Loc = v.Cursor.CurSelection[index]
v.Cursor.ResetSelection()
return true
}
return false
}
// Center centers the view on the cursor
func (v *View) Center(usePlugin bool) bool {
if usePlugin && !PreActionCall("Center", v) {
@@ -70,10 +77,7 @@ func (v *View) CursorUp(usePlugin bool) bool {
return false
}
if v.Cursor.HasSelection() {
v.Cursor.Loc = v.Cursor.CurSelection[0]
v.Cursor.ResetSelection()
}
v.deselect(0)
v.Cursor.Up()
if usePlugin {
@@ -88,10 +92,7 @@ func (v *View) CursorDown(usePlugin bool) bool {
return false
}
if v.Cursor.HasSelection() {
v.Cursor.Loc = v.Cursor.CurSelection[1]
v.Cursor.ResetSelection()
}
v.deselect(1)
v.Cursor.Down()
if usePlugin {
@@ -290,6 +291,8 @@ func (v *View) StartOfLine(usePlugin bool) bool {
return false
}
v.deselect(0)
v.Cursor.Start()
if usePlugin {
@@ -304,6 +307,8 @@ func (v *View) EndOfLine(usePlugin bool) bool {
return false
}
v.deselect(0)
v.Cursor.End()
if usePlugin {
@@ -354,6 +359,8 @@ func (v *View) CursorStart(usePlugin bool) bool {
return false
}
v.deselect(0)
v.Cursor.X = 0
v.Cursor.Y = 0
@@ -369,6 +376,8 @@ func (v *View) CursorEnd(usePlugin bool) bool {
return false
}
v.deselect(0)
v.Cursor.Loc = v.Buf.End()
if usePlugin {
@@ -587,21 +596,21 @@ func (v *View) IndentSelection(usePlugin bool) bool {
v.Buf.Insert(Loc{0, i}, Spaces(tabsize))
if i == start {
if v.Cursor.CurSelection[0].X > 0 {
v.Cursor.CurSelection[0] = v.Cursor.CurSelection[0].Move(tabsize, v.Buf)
v.Cursor.SetSelectionStart(v.Cursor.CurSelection[0].Move(tabsize, v.Buf))
}
}
if i == end {
v.Cursor.CurSelection[1] = Loc{endX + tabsize + 1, end}
v.Cursor.SetSelectionEnd(Loc{endX + tabsize + 1, end})
}
} else {
v.Buf.Insert(Loc{0, i}, "\t")
if i == start {
if v.Cursor.CurSelection[0].X > 0 {
v.Cursor.CurSelection[0] = v.Cursor.CurSelection[0].Move(1, v.Buf)
v.Cursor.SetSelectionStart(v.Cursor.CurSelection[0].Move(1, v.Buf))
}
}
if i == end {
v.Cursor.CurSelection[1] = Loc{endX + 2, end}
v.Cursor.SetSelectionEnd(Loc{endX + 2, end})
}
}
}
@@ -636,22 +645,22 @@ func (v *View) OutdentSelection(usePlugin bool) bool {
v.Buf.Remove(Loc{0, i}, Loc{1, i})
if i == start {
if v.Cursor.CurSelection[0].X > 0 {
v.Cursor.CurSelection[0] = v.Cursor.CurSelection[0].Move(-1, v.Buf)
v.Cursor.SetSelectionStart(v.Cursor.CurSelection[0].Move(-1, v.Buf))
}
}
if i == end {
v.Cursor.CurSelection[1] = Loc{endX - j, end}
v.Cursor.SetSelectionEnd(Loc{endX - j, end})
}
}
} else {
v.Buf.Remove(Loc{0, i}, Loc{1, i})
if i == start {
if v.Cursor.CurSelection[0].X > 0 {
v.Cursor.CurSelection[0] = v.Cursor.CurSelection[0].Move(-1, v.Buf)
v.Cursor.SetSelectionStart(v.Cursor.CurSelection[0].Move(-1, v.Buf))
}
}
if i == end {
v.Cursor.CurSelection[1] = Loc{endX, end}
v.Cursor.SetSelectionEnd(Loc{endX, end})
}
}
}
@@ -678,6 +687,9 @@ func (v *View) InsertTab(usePlugin bool) bool {
// Insert a tab
if v.Buf.Settings["tabstospaces"].(bool) {
tabSize := int(v.Buf.Settings["tabsize"].(float64))
if remainder := v.Cursor.Loc.X % tabSize; remainder != 0 {
tabSize = tabSize - remainder
}
v.Buf.Insert(v.Cursor.Loc, Spaces(tabSize))
for i := 0; i < tabSize; i++ {
v.Cursor.Right()
@@ -707,6 +719,8 @@ func (v *View) Save(usePlugin bool) bool {
if v.Buf.Path == "" {
filename, canceled := messenger.Prompt("Filename: ", "Save", NoCompletion)
if !canceled {
// the filename might or might not be quoted, so unquote first then join the strings.
filename = strings.Join(SplitCommandArgs(filename), " ")
v.Buf.Path = filename
v.Buf.Name = filename
} else {
@@ -836,7 +850,7 @@ func (v *View) Copy(usePlugin bool) bool {
}
if v.Cursor.HasSelection() {
clipboard.WriteAll(v.Cursor.GetSelection())
clipboard.WriteAll(v.Cursor.GetSelection(), "clipboard")
v.freshClip = true
messenger.Message("Copied selection")
}
@@ -859,10 +873,10 @@ func (v *View) CutLine(usePlugin bool) bool {
}
if v.freshClip == true {
if v.Cursor.HasSelection() {
if clip, err := clipboard.ReadAll(); err != nil {
if clip, err := clipboard.ReadAll("clipboard"); err != nil {
messenger.Error(err)
} else {
clipboard.WriteAll(clip + v.Cursor.GetSelection())
clipboard.WriteAll(clip+v.Cursor.GetSelection(), "clipboard")
}
}
} else if time.Since(v.lastCutTime)/time.Second > 10*time.Second || v.freshClip == false {
@@ -887,7 +901,7 @@ func (v *View) Cut(usePlugin bool) bool {
}
if v.Cursor.HasSelection() {
clipboard.WriteAll(v.Cursor.GetSelection())
clipboard.WriteAll(v.Cursor.GetSelection(), "clipboard")
v.Cursor.DeleteSelection()
v.Cursor.ResetSelection()
v.freshClip = true
@@ -946,18 +960,23 @@ func (v *View) Paste(usePlugin bool) bool {
return false
}
leadingWS := GetLeadingWhitespace(v.Buf.Line(v.Cursor.Y))
clip, _ := clipboard.ReadAll("clipboard")
v.paste(clip)
if v.Cursor.HasSelection() {
v.Cursor.DeleteSelection()
v.Cursor.ResetSelection()
if usePlugin {
return PostActionCall("Paste", v)
}
clip, _ := clipboard.ReadAll()
clip = strings.Replace(clip, "\n", "\n"+leadingWS, -1)
v.Buf.Insert(v.Cursor.Loc, clip)
v.Cursor.Loc = v.Cursor.Loc.Move(Count(clip), v.Buf)
v.freshClip = false
messenger.Message("Pasted clipboard")
return true
}
// PastePrimary pastes from the primary clipboard (only use on linux)
func (v *View) PastePrimary(usePlugin bool) bool {
if usePlugin && !PreActionCall("Paste", v) {
return false
}
clip, _ := clipboard.ReadAll("primary")
v.paste(clip)
if usePlugin {
return PostActionCall("Paste", v)
@@ -971,8 +990,8 @@ func (v *View) SelectAll(usePlugin bool) bool {
return false
}
v.Cursor.CurSelection[0] = v.Buf.Start()
v.Cursor.CurSelection[1] = v.Buf.End()
v.Cursor.SetSelectionStart(v.Buf.Start())
v.Cursor.SetSelectionEnd(v.Buf.End())
// Put the cursor at the beginning
v.Cursor.X = 0
v.Cursor.Y = 0
@@ -989,23 +1008,15 @@ func (v *View) OpenFile(usePlugin bool) bool {
return false
}
if v.CanClose("Continue? (y,n,s) ", 'y', 'n', 's') {
if v.CanClose() {
filename, canceled := messenger.Prompt("File to open: ", "Open", FileCompletion)
if canceled {
return false
}
home, _ := homedir.Dir()
filename = strings.Replace(filename, "~", home, 1)
file, err := ioutil.ReadFile(filename)
// the filename might or might not be quoted, so unquote first then join the strings.
filename = strings.Join(SplitCommandArgs(filename), " ")
var buf *Buffer
if err != nil {
// File does not exist -- create an empty buffer with that name
buf = NewBuffer([]byte{}, filename)
} else {
buf = NewBuffer(file, filename)
}
v.OpenBuffer(buf)
v.Open(filename)
if usePlugin {
return PostActionCall("OpenFile", v)
@@ -1089,6 +1100,8 @@ func (v *View) CursorPageUp(usePlugin bool) bool {
return false
}
v.deselect(0)
if v.Cursor.HasSelection() {
v.Cursor.Loc = v.Cursor.CurSelection[0]
v.Cursor.ResetSelection()
@@ -1107,6 +1120,8 @@ func (v *View) CursorPageDown(usePlugin bool) bool {
return false
}
v.deselect(0)
if v.Cursor.HasSelection() {
v.Cursor.Loc = v.Cursor.CurSelection[1]
v.Cursor.ResetSelection()
@@ -1250,7 +1265,7 @@ func (v *View) ShellMode(usePlugin bool) bool {
input, canceled := messenger.Prompt("$ ", "Shell", NoCompletion)
if !canceled {
// The true here is for openTerm to make the command interactive
HandleShellCommand(input, true)
HandleShellCommand(input, true, true)
if usePlugin {
return PostActionCall("ShellMode", v)
}
@@ -1285,7 +1300,7 @@ func (v *View) Quit(usePlugin bool) bool {
}
// Make sure not to quit if there are unsaved changes
if v.CanClose("Quit anyway? (y,n,s) ", 'y', 'n', 's') {
if v.CanClose() {
v.CloseBuffer()
if len(tabs[curTab].views) > 1 {
v.splitNode.Delete()
@@ -1322,6 +1337,39 @@ func (v *View) Quit(usePlugin bool) bool {
return false
}
// QuitAll quits the whole editor; all splits and tabs
func (v *View) QuitAll(usePlugin bool) bool {
if usePlugin && !PreActionCall("QuitAll", v) {
return false
}
closeAll := true
for _, tab := range tabs {
for _, v := range tab.views {
if !v.CanClose() {
closeAll = false
}
}
}
if closeAll {
for _, tab := range tabs {
for _, v := range tab.views {
v.CloseBuffer()
}
}
if usePlugin {
PostActionCall("QuitAll", v)
}
screen.Fini()
os.Exit(0)
}
return false
}
// AddTab adds a new tab with an empty buffer
func (v *View) AddTab(usePlugin bool) bool {
if usePlugin && !PreActionCall("AddTab", v) {
@@ -1420,6 +1468,62 @@ func (v *View) PreviousSplit(usePlugin bool) bool {
return false
}
var curMacro []interface{}
var recordingMacro bool
func (v *View) ToggleMacro(usePlugin bool) bool {
if usePlugin && !PreActionCall("ToggleMacro", v) {
return false
}
recordingMacro = !recordingMacro
if recordingMacro {
curMacro = []interface{}{}
messenger.Message("Recording")
} else {
messenger.Message("Stopped recording")
}
if usePlugin {
return PostActionCall("ToggleMacro", v)
}
return true
}
func (v *View) PlayMacro(usePlugin bool) bool {
if usePlugin && !PreActionCall("PlayMacro", v) {
return false
}
for _, action := range curMacro {
switch t := action.(type) {
case rune:
// Insert a character
if v.Cursor.HasSelection() {
v.Cursor.DeleteSelection()
v.Cursor.ResetSelection()
}
v.Buf.Insert(v.Cursor.Loc, string(t))
v.Cursor.Right()
for _, pl := range loadedPlugins {
_, err := Call(pl+".onRune", string(t), v)
if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") {
TermMessage(err)
}
}
case func(*View, bool) bool:
t(v, true)
}
}
if usePlugin {
return PostActionCall("PlayMacro", v)
}
return true
}
// None is no action
func None() bool {
return false

View File

@@ -8,19 +8,22 @@ import (
"github.com/mitchellh/go-homedir"
)
var pluginCompletions []func(string) []string
// This file is meant (for now) for autocompletion in command mode, not
// while coding. This helps micro autocomplete commands and then filenames
// for example with `vsplit filename`.
// FileComplete autocompletes filenames
func FileComplete(input string) (string, []string) {
dirs := strings.Split(input, "/")
var sep string = string(os.PathSeparator)
dirs := strings.Split(input, sep)
var files []os.FileInfo
var err error
if len(dirs) > 1 {
home, _ := homedir.Dir()
directories := strings.Join(dirs[:len(dirs)-1], "/")
directories := strings.Join(dirs[:len(dirs)-1], sep)
if strings.HasPrefix(directories, "~") {
directories = strings.Replace(directories, "~", home, 1)
}
@@ -35,7 +38,7 @@ func FileComplete(input string) (string, []string) {
for _, f := range files {
name := f.Name()
if f.IsDir() {
name += "/"
name += sep
}
if strings.HasPrefix(name, dirs[len(dirs)-1]) {
suggestions = append(suggestions, name)
@@ -45,13 +48,13 @@ func FileComplete(input string) (string, []string) {
var chosen string
if len(suggestions) == 1 {
if len(dirs) > 1 {
chosen = strings.Join(dirs[:len(dirs)-1], "/") + "/" + suggestions[0]
chosen = strings.Join(dirs[:len(dirs)-1], sep) + sep + suggestions[0]
} else {
chosen = suggestions[0]
}
} else {
if len(dirs) > 1 {
chosen = strings.Join(dirs[:len(dirs)-1], "/") + "/"
chosen = strings.Join(dirs[:len(dirs)-1], sep) + sep
}
}
@@ -122,3 +125,24 @@ func OptionComplete(input string) (string, []string) {
}
return chosen, suggestions
}
// MakeCompletion registeres a function from a plugin for autocomplete commands
func MakeCompletion(function string) Completion {
pluginCompletions = append(pluginCompletions, LuaFunctionComplete(function))
return Completion(-len(pluginCompletions))
}
// PluginComplete autocompletes from plugin function
func PluginComplete(complete Completion, input string) (chosen string, suggestions []string) {
idx := int(-complete) - 1
if len(pluginCompletions) <= idx {
return "", nil
}
suggestions = pluginCompletions[idx](input)
if len(suggestions) == 1 {
chosen = suggestions[0]
}
return
}

View File

@@ -1,11 +1,11 @@
package main
import (
"encoding/json"
"io/ioutil"
"os"
"strings"
"github.com/yosuke-furukawa/json5/encoding/json5"
"github.com/zyedidia/tcell"
)
@@ -55,6 +55,7 @@ var bindingActions = map[string]func(*View, bool) bool{
"IndentSelection": (*View).IndentSelection,
"OutdentSelection": (*View).OutdentSelection,
"Paste": (*View).Paste,
"PastePrimary": (*View).PastePrimary,
"SelectAll": (*View).SelectAll,
"OpenFile": (*View).OpenFile,
"Start": (*View).Start,
@@ -72,11 +73,14 @@ var bindingActions = map[string]func(*View, bool) bool{
"ShellMode": (*View).ShellMode,
"CommandMode": (*View).CommandMode,
"Quit": (*View).Quit,
"QuitAll": (*View).QuitAll,
"AddTab": (*View).AddTab,
"PreviousTab": (*View).PreviousTab,
"NextTab": (*View).NextTab,
"NextSplit": (*View).NextSplit,
"PreviousSplit": (*View).PreviousSplit,
"ToggleMacro": (*View).ToggleMacro,
"PlayMacro": (*View).PlayMacro,
// This was changed to InsertNewline but I don't want to break backwards compatibility
"InsertEnter": (*View).InsertNewline,
@@ -235,7 +239,7 @@ func InitBindings() {
return
}
err = json.Unmarshal(input, &parsed)
err = json5.Unmarshal(input, &parsed)
if err != nil {
TermMessage("Error reading bindings.json:", err.Error())
}
@@ -393,6 +397,8 @@ func DefaultBindings() map[string]string {
"CtrlBackslash": "NextTab",
"Home": "StartOfLine",
"End": "EndOfLine",
"CtrlHome": "CursorStart",
"CtrlEnd": "CursorEnd",
"PageUp": "CursorPageUp",
"PageDown": "CursorPageDown",
"CtrlG": "ToggleHelp",
@@ -404,6 +410,8 @@ func DefaultBindings() map[string]string {
"CtrlQ": "Quit",
"CtrlE": "CommandMode",
"CtrlW": "NextSplit",
"CtrlU": "ToggleMacro",
"CtrlJ": "PlayMacro",
// Emacs-style keybindings
"Alt-f": "WordRight",

View File

@@ -8,6 +8,8 @@ import (
"os/exec"
"os/signal"
"path/filepath"
"strconv"
"strings"
"time"
"unicode/utf8"
)
@@ -85,10 +87,36 @@ func NewBuffer(txt []byte, path string) *Buffer {
}
// Put the cursor at the first spot
cursorStartX := 0
cursorStartY := 0
// If -startpos LINE,COL was passed, use start position LINE,COL
if len(*flagStartPos) > 0 {
positions := strings.Split(*flagStartPos, ",")
if len(positions) == 2 {
lineNum, errPos1 := strconv.Atoi(positions[0])
colNum, errPos2 := strconv.Atoi(positions[1])
if errPos1 == nil && errPos2 == nil {
cursorStartX = colNum
cursorStartY = lineNum - 1
// Check to avoid line overflow
if cursorStartY > b.NumLines {
cursorStartY = b.NumLines - 1
} else if cursorStartY < 0 {
cursorStartY = 0
}
// Check to avoid column overflow
if cursorStartX > len(b.Line(cursorStartY)) {
cursorStartX = len(b.Line(cursorStartY))
} else if cursorStartX < 0 {
cursorStartX = 0
}
}
}
}
b.Cursor = Cursor{
Loc: Loc{
X: 0,
Y: 0,
X: cursorStartX,
Y: cursorStartY,
},
buf: b,
}
@@ -219,6 +247,7 @@ func (b *Buffer) Serialize() error {
// SaveAs saves the buffer to a specified path (filename), creating the file if it does not exist
func (b *Buffer) SaveAs(filename string) error {
b.FindFileType()
b.UpdateRules()
b.Name = filename
b.Path = filename
@@ -235,6 +264,7 @@ func (b *Buffer) SaveAs(filename string) error {
// SaveAsWithSudo is the same as SaveAs except it uses a neat trick
// with tee to use sudo so the user doesn't have to reopen micro with sudo
func (b *Buffer) SaveAsWithSudo(filename string) error {
b.FindFileType()
b.UpdateRules()
b.Name = filename
b.Path = filename

View File

@@ -16,7 +16,25 @@ type Colorscheme map[string]tcell.Style
// The current colorscheme
var colorscheme Colorscheme
var preInstalledColors = []string{"default", "simple", "solarized", "solarized-tc", "atom-dark-tc", "monokai", "gruvbox", "zenburn"}
var preInstalledColors = []string{"default", "simple", "solarized", "solarized-tc", "atom-dark-tc", "monokai", "gruvbox", "zenburn", "bubblegum"}
// ColorschemeExists checks if a given colorscheme exists
func ColorschemeExists(colorschemeName string) bool {
files, _ := ioutil.ReadDir(configDir)
for _, f := range files {
if f.Name() == colorschemeName+".micro" {
return true
}
}
for _, name := range preInstalledColors {
if name == colorschemeName {
return true
}
}
return false
}
// InitColorscheme picks and initializes the colorscheme when micro starts
func InitColorscheme() {
@@ -31,6 +49,7 @@ func LoadDefaultColorscheme() {
// LoadColorscheme loads the given colorscheme from a directory
func LoadColorscheme(colorschemeName, dir string) {
files, _ := ioutil.ReadDir(dir)
found := false
for _, f := range files {
if f.Name() == colorschemeName+".micro" {
text, err := ioutil.ReadFile(dir + "/" + f.Name())
@@ -39,6 +58,7 @@ func LoadColorscheme(colorschemeName, dir string) {
continue
}
colorscheme = ParseColorscheme(string(text))
found = true
}
}
@@ -50,8 +70,13 @@ func LoadColorscheme(colorschemeName, dir string) {
continue
}
colorscheme = ParseColorscheme(string(data))
found = true
}
}
if !found {
TermMessage(colorschemeName, "is not a valid colorscheme")
}
}
// ParseColorscheme parses the text definition for a colorscheme and returns the corresponding object

View File

@@ -2,6 +2,7 @@ package main
import (
"bytes"
"io"
"io/ioutil"
"os"
"os/exec"
@@ -225,7 +226,7 @@ func Bind(args []string) {
// Run runs a shell command in the background
func Run(args []string) {
// Run a shell command in the background (openTerm is false)
HandleShellCommand(strings.Join(args, " "), false)
HandleShellCommand(JoinCommandArgs(args...), false, true)
}
// Quit closes the main view
@@ -242,40 +243,20 @@ func Save(args []string) {
// Replace runs search and replace
func Replace(args []string) {
// This is a regex to parse the replace expression
// We allow no quotes if there are no spaces, but if you want to search
// for or replace an expression with spaces, you can add double quotes
r := regexp.MustCompile(`"[^"\\]*(?:\\.[^"\\]*)*"|[^\s]*`)
replaceCmd := r.FindAllString(strings.Join(args, " "), -1)
if len(replaceCmd) < 2 {
if len(args) < 2 {
// We need to find both a search and replace expression
messenger.Error("Invalid replace statement: " + strings.Join(args, " "))
return
}
var flags string
if len(replaceCmd) == 3 {
if len(args) == 3 {
// The user included some flags
flags = replaceCmd[2]
flags = args[2]
}
search := string(replaceCmd[0])
replace := string(replaceCmd[1])
// If the search and replace expressions have quotes, we need to remove those
if strings.HasPrefix(search, `"`) && strings.HasSuffix(search, `"`) {
search = search[1 : len(search)-1]
}
if strings.HasPrefix(replace, `"`) && strings.HasSuffix(replace, `"`) {
replace = replace[1 : len(replace)-1]
}
// We replace all escaped double quotes to real double quotes
search = strings.Replace(search, `\"`, `"`, -1)
replace = strings.Replace(replace, `\"`, `"`, -1)
// Replace some things so users can actually insert newlines and tabs in replacements
replace = strings.Replace(replace, "\\n", "\n", -1)
replace = strings.Replace(replace, "\\t", "\t", -1)
search := string(args[0])
replace := string(args[1])
regex, err := regexp.Compile(search)
if err != nil {
@@ -287,15 +268,13 @@ func Replace(args []string) {
view := CurView()
found := 0
for {
match := regex.FindStringIndex(view.Buf.String())
if match == nil {
break
}
found++
if strings.Contains(flags, "c") {
if strings.Contains(flags, "c") {
for {
// The 'check' flag was used
Search(search, view, true)
if !view.Cursor.HasSelection() {
break
}
view.Relocate()
if view.Buf.Settings["syntax"].(bool) {
view.matches = Match(view)
@@ -308,13 +287,14 @@ func Replace(args []string) {
view.Cursor.ResetSelection()
}
messenger.Reset()
return
break
}
if choice {
view.Cursor.DeleteSelection()
view.Buf.Insert(FromCharPos(match[0], view.Buf), replace)
view.Buf.Insert(view.Cursor.Loc, replace)
view.Cursor.ResetSelection()
messenger.Reset()
found++
} else {
if view.Cursor.HasSelection() {
searchStart = ToCharPos(view.Cursor.CurSelection[1], view.Buf)
@@ -323,7 +303,14 @@ func Replace(args []string) {
}
continue
}
} else {
}
} else {
for {
match := regex.FindStringIndex(view.Buf.String())
if match == nil {
break
}
found++
view.Buf.Replace(FromCharPos(match[0], view.Buf), FromCharPos(match[1], view.Buf), replace)
}
}
@@ -340,8 +327,8 @@ func Replace(args []string) {
// RunShellCommand executes a shell command and returns the output/error
func RunShellCommand(input string) (string, error) {
inputCmd := strings.Split(input, " ")[0]
args := strings.Split(input, " ")[1:]
inputCmd := SplitCommandArgs(input)[0]
args := SplitCommandArgs(input)[1:]
cmd := exec.Command(inputCmd, args...)
outputBytes := &bytes.Buffer{}
@@ -356,8 +343,8 @@ func RunShellCommand(input string) (string, error) {
// HandleShellCommand runs the shell command
// The openTerm argument specifies whether a terminal should be opened (for viewing output
// or interacting with stdin)
func HandleShellCommand(input string, openTerm bool) {
inputCmd := strings.Split(input, " ")[0]
func HandleShellCommand(input string, openTerm bool, waitToFinish bool) string {
inputCmd := SplitCommandArgs(input)[0]
if !openTerm {
// Simply run the command in the background and notify the user when it's done
messenger.Message("Running...")
@@ -382,12 +369,13 @@ func HandleShellCommand(input string, openTerm bool) {
screen.Fini()
screen = nil
args := strings.Split(input, " ")[1:]
args := SplitCommandArgs(input)[1:]
// Set up everything for the command
var outputBuf bytes.Buffer
cmd := exec.Command(inputCmd, args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stdout = io.MultiWriter(os.Stdout, &outputBuf)
cmd.Stderr = os.Stderr
// This is a trap for Ctrl-C so that it doesn't kill micro
@@ -400,26 +388,35 @@ func HandleShellCommand(input string, openTerm bool) {
}
}()
// Start the command
cmd.Start()
cmd.Wait()
err := cmd.Wait()
// This is just so we don't return right away and let the user press enter to return
TermMessage("")
output := outputBuf.String()
if err != nil {
output = err.Error()
}
if waitToFinish {
// This is just so we don't return right away and let the user press enter to return
TermMessage("")
}
// Start the screen back up
InitScreen()
return output
}
return ""
}
// HandleCommand handles input from the user
func HandleCommand(input string) {
inputCmd := strings.Split(input, " ")[0]
args := strings.Split(input, " ")[1:]
args := SplitCommandArgs(input)
inputCmd := args[0]
if _, ok := commands[inputCmd]; !ok {
messenger.Error("Unknown command ", inputCmd)
} else {
commands[inputCmd].action(args)
commands[inputCmd].action(args[1:])
}
}

View File

@@ -1,5 +1,7 @@
package main
import "github.com/zyedidia/clipboard"
// The Cursor struct stores the location of the cursor in the view
// The complicated part about the cursor is storing its location.
// The cursor must be displayed at an x, y location, but since the buffer
@@ -33,6 +35,24 @@ func (c *Cursor) ResetSelection() {
c.CurSelection[1] = c.buf.Start()
}
// SetSelectionStart sets the start of the selection
func (c *Cursor) SetSelectionStart(pos Loc) {
c.CurSelection[0] = pos
// Copy to primary clipboard for linux
if c.HasSelection() {
clipboard.WriteAll(c.GetSelection(), "primary")
}
}
// SetSelectionEnd sets the end of the selection
func (c *Cursor) SetSelectionEnd(pos Loc) {
c.CurSelection[1] = pos
// Copy to primary clipboard for linux
if c.HasSelection() {
clipboard.WriteAll(c.GetSelection(), "primary")
}
}
// HasSelection returns whether or not the user has selected anything
func (c *Cursor) HasSelection() bool {
return c.CurSelection[0] != c.CurSelection[1]
@@ -43,7 +63,7 @@ func (c *Cursor) DeleteSelection() {
if c.CurSelection[0].GreaterThan(c.CurSelection[1]) {
c.buf.Remove(c.CurSelection[1], c.CurSelection[0])
c.Loc = c.CurSelection[1]
} else if c.GetSelection() == "" {
} else if !c.HasSelection() {
return
} else {
c.buf.Remove(c.CurSelection[0], c.CurSelection[1])
@@ -62,12 +82,12 @@ func (c *Cursor) GetSelection() string {
// SelectLine selects the current line
func (c *Cursor) SelectLine() {
c.Start()
c.CurSelection[0] = c.Loc
c.SetSelectionStart(c.Loc)
c.End()
if c.buf.NumLines-1 > c.Y {
c.CurSelection[1] = c.Loc.Move(1, c.buf)
c.SetSelectionEnd(c.Loc.Move(1, c.buf))
} else {
c.CurSelection[1] = c.Loc
c.SetSelectionEnd(c.Loc)
}
c.OrigSelection = c.CurSelection
@@ -77,13 +97,13 @@ func (c *Cursor) SelectLine() {
func (c *Cursor) AddLineToSelection() {
if c.Loc.LessThan(c.OrigSelection[0]) {
c.Start()
c.CurSelection[0] = c.Loc
c.CurSelection[1] = c.OrigSelection[1]
c.SetSelectionStart(c.Loc)
c.SetSelectionEnd(c.OrigSelection[1])
}
if c.Loc.GreaterThan(c.OrigSelection[1]) {
c.End()
c.CurSelection[1] = c.Loc.Move(1, c.buf)
c.CurSelection[0] = c.OrigSelection[0]
c.SetSelectionEnd(c.Loc.Move(1, c.buf))
c.SetSelectionStart(c.OrigSelection[0])
}
if c.Loc.LessThan(c.OrigSelection[1]) && c.Loc.GreaterThan(c.OrigSelection[0]) {
@@ -98,8 +118,8 @@ func (c *Cursor) SelectWord() {
}
if !IsWordChar(string(c.RuneUnder(c.X))) {
c.CurSelection[0] = c.Loc
c.CurSelection[1] = c.Loc.Move(1, c.buf)
c.SetSelectionStart(c.Loc)
c.SetSelectionEnd(c.Loc.Move(1, c.buf))
c.OrigSelection = c.CurSelection
return
}
@@ -110,14 +130,14 @@ func (c *Cursor) SelectWord() {
backward--
}
c.CurSelection[0] = Loc{backward, c.Y}
c.SetSelectionStart(Loc{backward, c.Y})
c.OrigSelection[0] = c.CurSelection[0]
for forward < Count(c.buf.Line(c.Y))-1 && IsWordChar(string(c.RuneUnder(forward+1))) {
forward++
}
c.CurSelection[1] = Loc{forward, c.Y}.Move(1, c.buf)
c.SetSelectionEnd(Loc{forward, c.Y}.Move(1, c.buf))
c.OrigSelection[1] = c.CurSelection[1]
c.Loc = c.CurSelection[1]
}
@@ -136,8 +156,8 @@ func (c *Cursor) AddWordToSelection() {
backward--
}
c.CurSelection[0] = Loc{backward, c.Y}
c.CurSelection[1] = c.OrigSelection[1]
c.SetSelectionStart(Loc{backward, c.Y})
c.SetSelectionEnd(c.OrigSelection[1])
}
if c.Loc.GreaterThan(c.OrigSelection[1]) {
@@ -147,8 +167,8 @@ func (c *Cursor) AddWordToSelection() {
forward++
}
c.CurSelection[1] = Loc{forward, c.Y}.Move(1, c.buf)
c.CurSelection[0] = c.OrigSelection[0]
c.SetSelectionEnd(Loc{forward, c.Y}.Move(1, c.buf))
c.SetSelectionStart(c.OrigSelection[0])
}
c.Loc = c.CurSelection[1]
@@ -157,11 +177,11 @@ func (c *Cursor) AddWordToSelection() {
// SelectTo selects from the current cursor location to the given location
func (c *Cursor) SelectTo(loc Loc) {
if loc.GreaterThan(c.OrigSelection[0]) {
c.CurSelection[0] = c.OrigSelection[0]
c.CurSelection[1] = loc
c.SetSelectionStart(c.OrigSelection[0])
c.SetSelectionEnd(loc)
} else {
c.CurSelection[0] = loc
c.CurSelection[1] = c.OrigSelection[0]
c.SetSelectionStart(loc)
c.SetSelectionEnd(c.OrigSelection[0])
}
}

View File

@@ -38,6 +38,7 @@ var preInstalledSynFiles = []string{
"asm",
"awk",
"c",
"caddyfile",
"cmake",
"coffeescript",
"colortest",
@@ -47,6 +48,7 @@ var preInstalledSynFiles = []string{
"css",
"cython",
"d",
"dart",
"dot",
"erb",
"fish",
@@ -79,9 +81,11 @@ var preInstalledSynFiles = []string{
"man",
"markdown",
"mpdconf",
"micro",
"nanorc",
"nginx",
"ocaml",
"pascal",
"patch",
"peg",
"perl",

View File

@@ -6,7 +6,6 @@ import (
"fmt"
"os"
"strconv"
"strings"
"github.com/zyedidia/clipboard"
"github.com/zyedidia/tcell"
@@ -98,6 +97,7 @@ func (m *Messenger) Error(msg ...interface{}) {
// YesNoPrompt asks the user a yes or no question (waits for y or n) and returns the result
func (m *Messenger) YesNoPrompt(prompt string) (bool, bool) {
m.hasPrompt = true
m.Message(prompt)
_, h := screen.Size()
@@ -113,11 +113,14 @@ func (m *Messenger) YesNoPrompt(prompt string) (bool, bool) {
switch e.Key() {
case tcell.KeyRune:
if e.Rune() == 'y' {
m.hasPrompt = false
return true, false
} else if e.Rune() == 'n' {
m.hasPrompt = false
return false, false
}
case tcell.KeyCtrlC, tcell.KeyCtrlQ, tcell.KeyEscape:
m.hasPrompt = false
return false, true
}
}
@@ -126,6 +129,7 @@ func (m *Messenger) YesNoPrompt(prompt string) (bool, bool) {
// LetterPrompt gives the user a prompt and waits for a one letter response
func (m *Messenger) LetterPrompt(prompt string, responses ...rune) (rune, bool) {
m.hasPrompt = true
m.Message(prompt)
_, h := screen.Size()
@@ -142,11 +146,16 @@ func (m *Messenger) LetterPrompt(prompt string, responses ...rune) (rune, bool)
case tcell.KeyRune:
for _, r := range responses {
if e.Rune() == r {
m.Clear()
m.Reset()
m.hasPrompt = false
return r, false
}
}
case tcell.KeyCtrlC, tcell.KeyCtrlQ, tcell.KeyEscape:
m.Clear()
m.Reset()
m.hasPrompt = false
return ' ', true
}
}
@@ -196,7 +205,7 @@ func (m *Messenger) Prompt(prompt, historyType string, completionTypes ...Comple
response, canceled = m.response, false
m.history[historyType][len(m.history[historyType])-1] = response
case tcell.KeyTab:
args := strings.Split(m.response, " ")
args := SplitCommandArgs(m.response)
currentArgNum := len(args) - 1
currentArg := args[currentArgNum]
var completionType Completion
@@ -222,6 +231,8 @@ func (m *Messenger) Prompt(prompt, historyType string, completionTypes ...Comple
chosen, suggestions = HelpComplete(currentArg)
} else if completionType == OptionCompletion {
chosen, suggestions = OptionComplete(currentArg)
} else if completionType < NoCompletion {
chosen, suggestions = PluginComplete(completionType, currentArg)
}
if len(suggestions) > 1 {
@@ -229,10 +240,7 @@ func (m *Messenger) Prompt(prompt, historyType string, completionTypes ...Comple
}
if chosen != "" {
if len(args) > 1 {
chosen = " " + chosen
}
m.response = strings.Join(args[:len(args)-1], " ") + chosen
m.response = JoinCommandArgs(append(args[:len(args)-1], chosen)...)
m.cursorx = Count(m.response)
}
}
@@ -240,18 +248,19 @@ func (m *Messenger) Prompt(prompt, historyType string, completionTypes ...Comple
m.HandleEvent(event, m.history[historyType])
messenger.Clear()
m.Clear()
for _, v := range tabs[curTab].views {
v.Display()
}
DisplayTabs()
messenger.Display()
m.Display()
if len(suggestions) > 1 {
m.DisplaySuggestions(suggestions)
}
screen.Show()
}
m.Clear()
m.Reset()
return response, canceled
}
@@ -287,7 +296,7 @@ func (m *Messenger) HandleEvent(event tcell.Event, history []string) {
m.cursorx--
}
case tcell.KeyCtrlV:
clip, _ := clipboard.ReadAll()
clip, _ := clipboard.ReadAll("clipboard")
m.response = Insert(m.response, m.cursorx, clip)
m.cursorx += Count(clip)
case tcell.KeyRune:
@@ -347,11 +356,14 @@ func (m *Messenger) DisplaySuggestions(suggestions []string) {
func (m *Messenger) Display() {
_, h := screen.Size()
if m.hasMessage {
runes := []rune(m.message + m.response)
for x := 0; x < len(runes); x++ {
screen.SetContent(x, h-1, runes[x], nil, m.style)
if m.hasPrompt || globalSettings["infobar"].(bool) {
runes := []rune(m.message + m.response)
for x := 0; x < len(runes); x++ {
screen.SetContent(x, h-1, runes[x], nil, m.style)
}
}
}
if m.hasPrompt {
screen.ShowCursor(Count(m.message)+m.cursorx, h-1)
screen.Show()

View File

@@ -64,11 +64,11 @@ var (
)
// LoadInput determines which files should be loaded into buffers
// based on the input stored in os.Args
// based on the input stored in flag.Args()
func LoadInput() []*Buffer {
// There are a number of ways micro should start given its input
// 1. If it is given a files in os.Args, it should open those
// 1. If it is given a files in flag.Args(), it should open those
// 2. If there is no input file and the input is not a terminal, that means
// something is being piped in and the stdin should be opened in an
@@ -82,11 +82,12 @@ func LoadInput() []*Buffer {
var err error
var buffers []*Buffer
if len(os.Args) > 1 {
if len(flag.Args()) > 0 {
// Option 1
// We go through each file and load it
for i := 1; i < len(os.Args); i++ {
filename = os.Args[i]
for i := 0; i < len(flag.Args()); i++ {
filename = flag.Args()[i]
// Check that the file exists
if _, e := os.Stat(filename); e == nil {
// If it exists we load it into a buffer
@@ -195,10 +196,24 @@ func RedrawAll() {
}
// Passing -version as a flag will have micro print out the version number
var flagVersion = flag.Bool("version", false, "Show the version number")
var flagVersion = flag.Bool("version", false, "Show the version number and information")
var flagStartPos = flag.String("startpos", "", "LINE,COL to start the cursor at when opening a buffer.")
func main() {
flag.Usage = func() {
fmt.Println("Usage: micro [OPTIONS] [FILE]...")
fmt.Println("Micro's options can be set via command line arguments for quick adjustments. For real configuration, please use the bindings.json file (see 'help options').\n")
flag.PrintDefaults()
}
optionFlags := make(map[string]*string)
for k, v := range DefaultGlobalSettings() {
optionFlags[k] = flag.String(k, "", fmt.Sprintf("The %s option. Default value: '%v'", k, v))
}
flag.Parse()
if *flagVersion {
// If -version was passed
fmt.Println("Version:", Version)
@@ -220,6 +235,7 @@ func main() {
// Load the user's settings
InitGlobalSettings()
InitCommands()
InitBindings()
@@ -267,6 +283,12 @@ func main() {
}
}
for k, v := range optionFlags {
if *v != "" {
SetOption(k, *v)
}
}
// Load all the plugin stuff
// We give plugins access to a bunch of variables here which could be useful to them
L.SetGlobal("OS", luar.New(L, runtime.GOOS))
@@ -284,6 +306,8 @@ func main() {
L.SetGlobal("HandleCommand", luar.New(L, HandleCommand))
L.SetGlobal("HandleShellCommand", luar.New(L, HandleShellCommand))
L.SetGlobal("GetLeadingWhitespace", luar.New(L, GetLeadingWhitespace))
L.SetGlobal("MakeCompletion", luar.New(L, MakeCompletion))
L.SetGlobal("NewBuffer", luar.New(L, NewBuffer))
// Used for asynchronous jobs
L.SetGlobal("JobStart", luar.New(L, JobStart))
@@ -338,20 +362,22 @@ func main() {
// If the user left clicked we check a couple things
_, h := screen.Size()
x, y := e.Position()
if y == h-1 && messenger.message != "" {
if y == h-1 && messenger.message != "" && globalSettings["infobar"].(bool) {
// If the user clicked in the bottom bar, and there is a message down there
// we copy it to the clipboard.
// Often error messages are displayed down there so it can be useful to easily
// copy the message
clipboard.WriteAll(messenger.message)
clipboard.WriteAll(messenger.message, "primary")
continue
}
// We loop through each view in the current tab and make sure the current view
// it the one being clicked in
for _, v := range tabs[curTab].views {
if x >= v.x && x < v.x+v.width && y >= v.y && y < v.y+v.height {
tabs[curTab].curView = v.Num
if CurView().mouseReleased {
// We loop through each view in the current tab and make sure the current view
// is the one being clicked in
for _, v := range tabs[curTab].views {
if x >= v.x && x < v.x+v.width && y >= v.y && y < v.y+v.height {
tabs[curTab].curView = v.Num
}
}
}
}

View File

@@ -85,6 +85,30 @@ func LuaFunctionCommand(function string) func([]string) {
}
}
// LuaFunctionComplete returns a function which can be used for autocomplete in plugins
func LuaFunctionComplete(function string) func(string) []string {
return func(input string) (result []string) {
res, err := Call(function, input)
if err != nil {
TermMessage(err)
}
if tbl, ok := res.(*lua.LTable); !ok {
TermMessage(function, "should return a table of strings")
} else {
for i := 1; i <= tbl.Len(); i++ {
val := tbl.RawGetInt(i)
if v, ok := val.(lua.LString); !ok {
TermMessage(function, "should return a table of strings")
} else {
result = append(result, string(v))
}
}
}
return result
}
}
func LuaFunctionJob(function string) func(string, ...string) {
return func(output string, args ...string) {
_, err := Call(function, unpack(append([]string{output}, args...))...)

File diff suppressed because one or more lines are too long

View File

@@ -125,8 +125,8 @@ func Search(searchStr string, v *View, down bool) {
return
}
v.Cursor.CurSelection[0] = FromCharPos(charPos+runePos(match[0], str), v.Buf)
v.Cursor.CurSelection[1] = FromCharPos(charPos+runePos(match[1], str), v.Buf)
v.Cursor.SetSelectionStart(FromCharPos(charPos+runePos(match[0], str), v.Buf))
v.Cursor.SetSelectionEnd(FromCharPos(charPos+runePos(match[1], str), v.Buf))
v.Cursor.Loc = v.Cursor.CurSelection[1]
if v.Relocate() {
v.matches = Match(v)

View File

@@ -1,7 +1,6 @@
package main
import (
"encoding/json"
"errors"
"io/ioutil"
"os"
@@ -9,6 +8,7 @@ import (
"strconv"
"strings"
"github.com/yosuke-furukawa/json5/encoding/json5"
"github.com/zyedidia/glob"
)
@@ -30,7 +30,7 @@ func InitGlobalSettings() {
return
}
err = json.Unmarshal(input, &parsed)
err = json5.Unmarshal(input, &parsed)
if err != nil {
TermMessage("Error reading settings.json:", err.Error())
}
@@ -70,7 +70,7 @@ func InitLocalSettings(buf *Buffer) {
return
}
err = json.Unmarshal(input, &parsed)
err = json5.Unmarshal(input, &parsed)
if err != nil {
TermMessage("Error reading settings.json:", err.Error())
}
@@ -110,7 +110,7 @@ func WriteSettings(filename string) error {
return err
}
err = json.Unmarshal(input, &parsed)
err = json5.Unmarshal(input, &parsed)
if err != nil {
TermMessage("Error reading settings.json:", err.Error())
}
@@ -125,8 +125,8 @@ func WriteSettings(filename string) error {
}
}
txt, _ := json.MarshalIndent(parsed, "", " ")
err = ioutil.WriteFile(filename, txt, 0644)
txt, _ := json5.MarshalIndent(parsed, "", " ")
err = ioutil.WriteFile(filename, append(txt, '\n'), 0644)
}
return err
}
@@ -169,6 +169,7 @@ func DefaultGlobalSettings() map[string]interface{} {
"cursorline": true,
"ignorecase": false,
"indentchar": " ",
"infobar": true,
"ruler": true,
"savecursor": false,
"saveundo": false,
@@ -207,6 +208,12 @@ func DefaultLocalSettings() map[string]interface{} {
// is local only it will set the local version
// Use setlocal to force an option to be set locally
func SetOption(option, value string) error {
if option == "colorscheme" {
if !ColorschemeExists(value) {
return errors.New(value + " is not a valid colorscheme")
}
}
if _, ok := globalSettings[option]; !ok {
if _, ok := CurView().Buf.Settings[option]; !ok {
return errors.New("Invalid option")
@@ -244,6 +251,12 @@ func SetOption(option, value string) error {
}
}
if option == "infobar" {
for _, tab := range tabs {
tab.Resize()
}
}
if _, ok := CurView().Buf.Settings[option]; ok {
for _, tab := range tabs {
for _, view := range tab.views {

View File

@@ -146,9 +146,7 @@ func (s *SplitTree) ResizeSplits() {
n.view.y = s.y + n.view.height*i
n.view.x = s.x
}
// n.view.ToggleStatusLine()
_, screenH := screen.Size()
if n.view.Buf.Settings["statusline"].(bool) || (n.view.y+n.view.height) != screenH-1 {
if n.view.Buf.Settings["statusline"].(bool) {
n.view.height--
}

View File

@@ -31,7 +31,12 @@ func NewTabFromView(v *View) *Tab {
w, h := screen.Size()
t.tree.width = w
t.tree.height = h - 1
t.tree.height = h
if globalSettings["infobar"].(bool) {
t.tree.height--
}
return t
}
@@ -49,7 +54,12 @@ func (t *Tab) Cleanup() {
func (t *Tab) Resize() {
w, h := screen.Size()
t.tree.width = w
t.tree.height = h - 1
t.tree.height = h
if globalSettings["infobar"].(bool) {
t.tree.height--
}
t.tree.ResizeSplits()
}

View File

@@ -1,8 +1,11 @@
package main
import (
"bytes"
"os"
"path/filepath"
"reflect"
"runtime"
"strconv"
"strings"
"time"
@@ -217,3 +220,77 @@ func Abs(n int) int {
}
return n
}
// FuncName returns the name of a given function object
func FuncName(i interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}
// SplitCommandArgs seperates multiple command arguments which may be quoted.
// The returned slice contains at least one string
func SplitCommandArgs(input string) []string {
var result []string
curArg := new(bytes.Buffer)
inQuote := false
escape := false
appendResult := func() {
str := curArg.String()
inQuote = false
escape = false
if strings.HasPrefix(str, `"`) && strings.HasSuffix(str, `"`) {
if unquoted, err := strconv.Unquote(str); err == nil {
str = unquoted
}
}
result = append(result, str)
curArg.Reset()
}
for _, r := range input {
if r == ' ' && !inQuote {
appendResult()
} else {
curArg.WriteRune(r)
if r == '"' && !inQuote {
inQuote = true
} else {
if inQuote && !escape {
if r == '"' {
inQuote = false
}
if r == '\\' {
escape = true
continue
}
}
}
}
escape = false
}
appendResult()
return result
}
// JoinCommandArgs joins multiple command arguments and quote the strings if needed.
func JoinCommandArgs(args ...string) string {
buf := new(bytes.Buffer)
first := true
for _, arg := range args {
if first {
first = false
} else {
buf.WriteRune(' ')
}
quoted := strconv.Quote(arg)
if quoted[1:len(quoted)-1] != arg || strings.ContainsRune(arg, ' ') {
buf.WriteString(quoted)
} else {
buf.WriteString(arg)
}
}
return buf.String()
}

View File

@@ -1,6 +1,9 @@
package main
import "testing"
import (
"reflect"
"testing"
)
func TestNumOccurences(t *testing.T) {
var tests = []struct {
@@ -63,3 +66,48 @@ func TestIsWordChar(t *testing.T) {
t.Errorf("IsWordChar(\n)) = true")
}
}
func TestJoinAndSplitCommandArgs(t *testing.T) {
tests := []struct {
Query []string
Wanted string
}{
{[]string{`test case`}, `"test case"`},
{[]string{`quote "test"`}, `"quote \"test\""`},
{[]string{`slash\\\ test`}, `"slash\\\\\\ test"`},
{[]string{`path 1`, `path\" 2`}, `"path 1" "path\\\" 2"`},
{[]string{`foo`}, `foo`},
{[]string{`foo\"bar`}, `"foo\\\"bar"`},
{[]string{``}, ``},
{[]string{`"`}, `"\""`},
{[]string{`a`, ``}, `a `},
{[]string{``, ``, ``, ``}, ` `},
{[]string{"\n"}, `"\n"`},
{[]string{"foo\tbar"}, `"foo\tbar"`},
}
for i, test := range tests {
if result := JoinCommandArgs(test.Query...); test.Wanted != result {
t.Errorf("JoinCommandArgs failed at Test %d\nGot: %q", i, result)
}
if result := SplitCommandArgs(test.Wanted); !reflect.DeepEqual(test.Query, result) {
t.Errorf("SplitCommandArgs failed at Test %d\nGot: `%q`", i, result)
}
}
splitTests := []struct {
Query string
Wanted []string
}{
{`"hallo""Welt"`, []string{`"hallo""Welt"`}},
{`\"`, []string{`\"`}},
{`"\"`, []string{`"\"`}},
}
for i, test := range splitTests {
if result := SplitCommandArgs(test.Query); !reflect.DeepEqual(test.Wanted, result) {
t.Errorf("SplitCommandArgs failed at Split-Test %d\nGot: `%q`", i, result)
}
}
}

View File

@@ -1,11 +1,13 @@
package main
import (
"io/ioutil"
"strconv"
"strings"
"time"
"github.com/mattn/go-runewidth"
"github.com/mitchellh/go-homedir"
"github.com/zyedidia/tcell"
)
@@ -84,7 +86,7 @@ type View struct {
// NewView returns a new fullscreen view
func NewView(buf *Buffer) *View {
screenW, screenH := screen.Size()
return NewViewWidthHeight(buf, screenW, screenH-1)
return NewViewWidthHeight(buf, screenW, screenH)
}
// NewViewWidthHeight returns a new view with the specified width and height
@@ -145,6 +147,20 @@ func (v *View) ToggleTabbar() {
}
}
func (v *View) paste(clip string) {
leadingWS := GetLeadingWhitespace(v.Buf.Line(v.Cursor.Y))
if v.Cursor.HasSelection() {
v.Cursor.DeleteSelection()
v.Cursor.ResetSelection()
}
clip = strings.Replace(clip, "\n", "\n"+leadingWS, -1)
v.Buf.Insert(v.Cursor.Loc, clip)
v.Cursor.Loc = v.Cursor.Loc.Move(Count(clip), v.Buf)
v.freshClip = false
messenger.Message("Pasted clipboard")
}
// ScrollUp scrolls the view up n lines (if possible)
func (v *View) ScrollUp(n int) {
// Try to scroll by n but if it would overflow, scroll by 1
@@ -168,16 +184,15 @@ func (v *View) ScrollDown(n int) {
// CanClose returns whether or not the view can be closed
// If there are unsaved changes, the user will be asked if the view can be closed
// causing them to lose the unsaved changes
// The message is what to print after saying "You have unsaved changes. "
func (v *View) CanClose(msg string, responses ...rune) bool {
func (v *View) CanClose() bool {
if v.Buf.IsModified {
char, canceled := messenger.LetterPrompt("You have unsaved changes. "+msg, responses...)
char, canceled := messenger.LetterPrompt("Save changes to "+v.Buf.Name+" before closing? (y,n,esc) ", 'y', 'n')
if !canceled {
if char == 'y' {
return true
} else if char == 's' {
v.Save(true)
return true
} else if char == 'n' {
return true
}
}
} else {
@@ -208,6 +223,22 @@ func (v *View) OpenBuffer(buf *Buffer) {
v.lastClickTime = time.Time{}
}
func (v *View) Open(filename string) {
home, _ := homedir.Dir()
filename = strings.Replace(filename, "~", home, 1)
file, err := ioutil.ReadFile(filename)
var buf *Buffer
if err != nil {
messenger.Message(err.Error())
// File does not exist -- create an empty buffer with that name
buf = NewBuffer([]byte{}, filename)
} else {
buf = NewBuffer(file, filename)
}
v.OpenBuffer(buf)
}
// CloseBuffer performs any closing functions on the buffer
func (v *View) CloseBuffer() {
if v.Buf != nil {
@@ -217,7 +248,7 @@ func (v *View) CloseBuffer() {
// ReOpen reloads the current buffer
func (v *View) ReOpen() {
if v.CanClose("Continue? (y,n,s) ", 'y', 'n', 's') {
if v.CanClose() {
screen.Clear()
v.Buf.ReOpen()
v.Relocate()
@@ -326,6 +357,10 @@ func (v *View) HandleEvent(event tcell.Event) {
TermMessage(err)
}
}
if recordingMacro {
curMacro = append(curMacro, e.Rune())
}
} else {
for key, actions := range bindings {
if e.Key() == key.keyCode {
@@ -338,13 +373,36 @@ func (v *View) HandleEvent(event tcell.Event) {
relocate = false
for _, action := range actions {
relocate = action(v, true) || relocate
funcName := FuncName(action)
if funcName != "main.(*View).ToggleMacro" && funcName != "main.(*View).PlayMacro" {
if recordingMacro {
curMacro = append(curMacro, action)
}
}
}
}
}
}
}
case *tcell.EventPaste:
relocate = v.Paste(true)
if !PreActionCall("Paste", v) {
break
}
leadingWS := GetLeadingWhitespace(v.Buf.Line(v.Cursor.Y))
if v.Cursor.HasSelection() {
v.Cursor.DeleteSelection()
v.Cursor.ResetSelection()
}
clip := e.Text()
clip = strings.Replace(clip, "\n", "\n"+leadingWS, -1)
v.Buf.Insert(v.Cursor.Loc, clip)
v.Cursor.Loc = v.Cursor.Loc.Move(Count(clip), v.Buf)
v.freshClip = false
messenger.Message("Pasted clipboard")
PostActionCall("Paste", v)
case *tcell.EventMouse:
x, y := e.Position()
x -= v.lineNumOffset - v.leftCol + v.x
@@ -394,9 +452,13 @@ func (v *View) HandleEvent(event tcell.Event) {
} else if v.doubleClick {
v.Cursor.AddWordToSelection()
} else {
v.Cursor.CurSelection[1] = v.Cursor.Loc
v.Cursor.SetSelectionEnd(v.Cursor.Loc)
}
}
case tcell.Button2:
// Middle mouse button was clicked,
// We should paste primary
v.PastePrimary(true)
case tcell.ButtonNone:
// Mouse event with no click
if !v.mouseReleased {
@@ -410,7 +472,7 @@ func (v *View) HandleEvent(event tcell.Event) {
if !v.doubleClick && !v.tripleClick {
v.MoveToMouseClick(x, y)
v.Cursor.CurSelection[1] = v.Cursor.Loc
v.Cursor.SetSelectionEnd(v.Cursor.Loc)
}
v.mouseReleased = true
}

View File

@@ -0,0 +1,19 @@
color-link default "241,231"
color-link comment "246,231"
color-link constant "130,231"
color-link constant.string "136,231"
color-link constant.number "131,231"
color-link identifier "133,231"
color-link statement "32,231"
color-link preproc "28,231"
color-link type "61,231"
color-link special "167,231"
color-link error "231, 160"
color-link underlined "underline 241,231"
color-link todo "246,231"
color-link statusline "241,254"
color-link gutter-error "197,231"
color-link gutter-warning "134,231"
color-link line-number "246,254"
color-link cursor-line "254"

View File

@@ -3,6 +3,12 @@
Micro is a terminal-based text editor that aims to be easy to use and intuitive,
while also taking advantage of the full capabilities of modern terminals.
*Press CtrlQ to quit, and CtrlS to save.*
If you want to see all the keybindings press CtrlE and type `help keybindings`.
See the next section for more information about documentation and help.
### Accessing more help
Micro has a built-in help system much like Vim's (although less extensive).

View File

@@ -50,6 +50,8 @@ you can rebind them to your liking.
"CtrlBackslash": "NextTab",
"Home": "Start",
"End": "End",
"CtrlHome": "CursorStart",
"CtrlEnd": "CursorEnd",
"PageUp": "CursorPageUp",
"PageDown": "CursorPageDown",
"CtrlG": "ToggleHelp",
@@ -61,6 +63,8 @@ you can rebind them to your liking.
"CtrlQ": "Quit",
"CtrlE": "CommandMode",
"CtrlW": "NextSplit",
"CtrlU": "ToggleMacro",
"CtrlJ": "PlayMacro",
// Emacs-style keybindings
"Alt-f": "WordRight",
@@ -169,11 +173,14 @@ ClearStatus
ShellMode
CommandMode
Quit
QuitAll
AddTab
PreviousTab
NextTab
NextSplit
PreviousSplit
ToggleMacro
PlayMacro
```
Here is the list of all possible keys you can bind:

View File

@@ -31,6 +31,11 @@ Here are the options that you can set:
default value: ` `
* `infobar`: enables the line at the bottom of the editor where messages are printed.
This option is `global only`.
default value: `on`
* `filetype`: sets the filetype for the current buffer. This setting is `local only`
default value: this will be automatically set depending on the file you have open

View File

@@ -37,7 +37,7 @@ for example turning off `tabstospaces` only for Go files when they are opened.
---
There are a number of functions and variables that are available to you in
oder to access the inner workings of micro. Here is a list (the type signatures
order to access the inner workings of micro. Here is a list (the type signatures
for functions are given using Go's type system):
* `OS`: variable which gives the OS micro is currently running on (this is the same
@@ -66,12 +66,17 @@ as Go's GOOS variable, so `darwin`, `windows`, `linux`, `freebsd`...)
creates a command with `name` which will call `function` when executed.
Use 0 for completions to get NoCompletion.
* `MakeCompletion(function string)`:
creates a `Completion` to use with `MakeCommand`.
* `CurView()`: returns the current view
* `HandleCommand(cmd string)`: runs the given command
* `HandleShellCommand(shellCmd string, interactive bool)`: runs the given shell
command
* `HandleShellCommand(shellCmd string, interactive bool, waitToClose bool)`: runs the given shell
command. The `interactive` bool specifies whether the command should run in the background. The
`waitToClose` bool only applies if `interactive` is true and means that it should wait before
returning to the editor.
* `JobStart(cmd string, onStdout, onStderr, onExit string, userargs ...string)`:
Starts running the given shell command in the background. `onStdout` `onStderr` and `onExit`
@@ -104,6 +109,36 @@ The possible methods which you can call using the `messenger` variable are:
If you want a standard prompt, just use `messenger.Prompt(prompt, "", 0)`
# Autocomplete command arguments
See this example to learn how to use `MakeCompletion` and `MakeCommand`
```lua
local function StartsWith(String,Start)
String = String:upper()
Start = Start:upper()
return string.sub(String,1,string.len(Start))==Start
end
function complete(input)
local allCompletions = {"Hello", "World", "Foo", "Bar"}
local result = {}
for i,v in pairs(allCompletions) do
if StartsWith(v, input) then
table.insert(result, v)
end
end
return result
end
function foo(arg)
messenger:Message(arg)
end
MakeCommand("foo", "example.foo", MakeCompletion("example.complete"))
```
# Default plugins
For examples of plugins, see the default plugins `linter`, `go`, and `autoclose`.

View File

@@ -1,7 +1,7 @@
# Tutorial
This is a brief intro to micro's configuration system that will will give some
simple examples showing how to configure settings, rebind keys,
This is a brief intro to micro's configuration system that will give some
simple examples showing how to configure settings, rebind keys,
and use `init.lua` to configure micro to your liking.
Hopefully you'll find this useful.
@@ -80,7 +80,7 @@ You can do that by putting the following in `init.lua`:
function gorun()
local buf = CurView().Buf -- The current buffer
if buf:FileType() == "go" then
HandleShellCommand("go run " .. buf.Path, true) -- true means don't run it in the background
HandleShellCommand("go run " .. buf.Path, true, true) -- the first true means don't run it in the background
end
end

View File

@@ -2,10 +2,14 @@ if GetOption("linter") == nil then
AddOption("linter", true)
end
MakeCommand("lint", "linter.runLinter", 0)
MakeCommand("lint", "linter.lintCommand", 0)
function lintCommand()
CurView():Save(false)
runLinter()
end
function runLinter()
CurView():Save(false)
local ft = CurView().Buf:FileType()
local file = CurView().Buf.Path
local devnull = "/dev/null"

View File

@@ -8,8 +8,6 @@ Micro syntax files are almost identical to Nano's, except for some key differenc
* Micro does not use `icolor`. Instead, for a case insensitive match, use the case insensitive flag (`i`) in the regular expression
* For example, `icolor green ".*"` would become `color green (i) ".*"`
* Micro does not support `start="..." end="..."`. Instead use the `s` flag to match newlines and put `.*?` in the middle
* For example `color green start="hello" end="world"` would become `color green (s) "hello.*?world"`
# Using with colorschemes
@@ -29,6 +27,7 @@ Here is a list of the files that have been converted to properly use colorscheme
* rust
* java
* javascript
* pascal
* python
* ruby
* sh

View File

@@ -1,17 +1,93 @@
## Here is an example for assembler.
##
## Made by Nickolay Ilyushin <nickolay02@inbox.ru>. Next line is from previous (first) version (no need for modifications :P)
syntax "asm" "\.(S|s|asm)$"
color red "\<[A-Z_]{2,}\>"
color brightgreen "\.(data|subsection|text)"
color green "\.(align|file|globl|global|hidden|section|size|type|weak)"
color brightyellow "\.(ascii|asciz|byte|double|float|hword|int|long|short|single|struct|word)"
brightred (i) "^[[:space:]]*[.0-9A-Z_]*:"
color brightcyan "^[[:space:]]*#[[:space:]]*(define|undef|include|ifn?def|endif|elif|else|if|warning|error)"
## Highlight strings (note: VERY resource intensive)
color brightyellow "<[^= ]*>" ""(\\.|[^"])*""
color brightyellow start=""(\\.|[^"])*\\[[:space:]]*$" end="^(\\.|[^"])*""
## Highlight comments
color brightblue "//.*"
color brightblue start="/\*" end="\*/"
## Highlight trailing whitespace
color ,green "[[:space:]]+$"
# This file is made for NASM assembly
## Instructions
# x86
color statement "\b(?i)(mov|aaa|aad|aam|aas|adc|add|and|call|cbw|clc|cld|cli|cmc|cmp|cmpsb|cmpsw|cwd|daa|das|dec|div|esc|hlt|idiv|imul|in|inc|int|into|iret|ja|jae|jb|jbe|jc|je|jg|jge|jl|jle|jna|jnae|jnb|jnbe|jnc|jne|jng|jnge|jnl|jnle|jno|jnp|jns|jnz|jo|jp|jpe|jpo|js|jz|jcxz|jmp|lahf|lds|lea|les|lock|lodsb|lodsw|loop|loope|loopne|loopnz|loopz|movsb|movsw|mul|neg|nop|or|pop|popf|push|pushf|rcl|rcr|rep|repe|repne|repnz|repz|ret|retn|retf|rol|ror|sahf|sal|sar|sbb|scasb|scasw|shl|shr|stc|std|sti|stosb|stosw|sub|test|wait|xchg|xlat|xor)(?-i)\b"
color statement "\b(?i)(bound|enter|ins|leave|outs|popa|pusha)(?-i)\b"
color statement "\b(?i)(arpl|clts|lar|lgdt|lidt|lldt|lmsw|loadall|lsl|ltr|sgdt|sidt|sldt|smsw|str|verr|verw)(?-i)\b"
color statement "\b(?i)(bsf|bsr|bt|btc|btr|bts|cdq|cmpsd|cwde|insd|iret|iretd|iretf|jecxz|lfs|lgs|lss|lodsd|loopw|loopew|loopnew|loopnzw|loopzw|loopd|looped|loopned|loopnzd|loopzd|cr|tr|dr|movsd|movsx|movzx|outsd|popad|popfd|pushad|pushfd|scasd|seta|setae|setb|setbe|setc|sete|setg|setge|setl|setle|setna|setnae|setnb|setnbe|setnc|setne|setng|setnge|setnl|setnle|setno|setnp|setns|setnz|seto|setp|setpe|setpo|sets|setz|shdl|shrd|stosd)(?-i)\b"
color statement "\b(?i)(bswap|cmpxcgh|invd|invlpg|wbinvd|xadd)(?-i)\b"
color statement "\b(?i)(cpuid|cmpxchg8b|rdmsr|rdtsc|wrmsr|rsm)(?-i)\b"
color statement "\b(?i)(rdpmc)(?-i)\b"
color statement "\b(?i)(syscall|sysret)(?-i)\b"
color statement "\b(?i)(cmova|cmovae|cmovb|cmovbe|cmovc|cmove|cmovg|cmovge|cmovl|cmovle|cmovna|cmovnae|cmovnb|cmovnbe|cmovnc|cmovne|cmovng|cmovnge|cmovnle|cmovno|cmovpn|cmovns|cmovnz|cmovo|cmovp|cmovpe|cmovpo|cmovs|cmovz|sysenter|sysexit|ud2)(?-i)\b"
color statement "\b(?i)(maskmovq|movntps|movntq|prefetch0|prefetch1|prefetch2|prefetchnta|sfence)(?-i)\b"
color statement "\b(?i)(clflush|lfence|maskmovdqu|mfence|movntdq|movnti|movntpd|pause)(?-i)\b"
color statement "\b(?i)(monitor|mwait)(?-i)\b"
color statement "\b(?i)(cdqe|cqo|cmpsq|cmpxchg16b|iretq|jrcxz|lodsq|movsdx|popfq|pushfq|rdtscp|scasq|stosq|swapgs)(?-i)\b"
color statement "\b(?i)(clgi|invlpga|skinit|stgi|vmload|vmmcall|vmrun|vmsave)(?-i)\b"
color statement "\b(?i)(vmptrdl|vmptrst|vmclear|vmread|vmwrite|vmcall|vmlaunch|vmresume|vmxoff|vmxon)(?-i)\b"
color statement "\b(?i)(lzcnt|popcnt)(?-i)\b"
color statement "\b(?i)(bextr|blcfill|blci|blcic|blcmask|blcs|blsfill|blsic|t1mskc|tzmsk)(?-i)\b"
# x87
color statement "\b(?i)(f2xm1|fabs|fadd|faddp|fbld|fbstp|fchs|fclex|fcom|fcomp|fcompp|fdecstp|fdisi|fdiv|fvidp|fdivr|fdivrp|feni|ffree|fiadd|ficom|ficomp|fidiv|fidivr|fild|fimul|fincstp|finit|fist|fistp|fisub|fisubr|fld|fld1|fldcw|fldenv|fldenvw|fldl2e|fldl2t|fldlg2|fldln2|fldpi|fldz|fmul|fmulp|fnclex|fndisi|fneni|fninit|fnop|fnsave|fnsavenew|fnstcw|fnstenv|fnstenvw|fnstsw|fpatan|fprem|fptan|frndint|frstor|frstorw|fsave|fsavew|fscale|fsqrt|fst|fstcw|fstenv|fstenvw|fstp|fstpsw|fsub|fsubp|fsubr|fsubrp|ftst|fwait|fxam|fxch|fxtract|fyl2x|fyl2xp1)(?-i)\b"
color statement "\b(?i)(fsetpm)(?-i)\b"
color statement "\b(?i)(fcos|fldenvd|fsaved|fstenvd|fprem1|frstord|fsin|fsincos|fstenvd|fucom|fucomp|fucompp)(?-i)\b"
color statement "\b(?i)(fcmovb|fcmovbe|fcmove|fcmove|fcmovnb|fcmovnbe|fcmovne|fcmovnu|fcmovu)(?-i)\b"
color statement "\b(?i)(fcomi|fcomip|fucomi|fucomip)(?-i)\b"
color statement "\b(?i)(fxrstor|fxsave)(?-i)\b"
color statement "\b(?i)(fisttp)(?-i)\b"
color statement "\b(?i)(ffreep)(?-i)\b"
# SIMD
color statement "\b(?i)(emms|movd|movq|packssdw|packsswb|packuswb|paddb|paddw|paddd|paddsb|paddsw|paddusb|paddusw|pand|pandn|por|pxor|pcmpeqb|pcmpeqw|pcmpeqd|pcmpgtb|pcmpgtw|pcmpgtd|pmaddwd|pmulhw|pmullw|psllw|pslld|psllq|psrad|psraw|psrlw|psrld|psrlq|psubb|psubw|psubd|psubsb|psubsw|psubusb|punpckhbw|punpckhwd|punpckhdq|punkcklbw|punpckldq|punpcklwd)(?-i)\b"
color statement "\b(?i)(paveb|paddsiw|pmagw|pdistib|psubsiw|pmwzb|pmulhrw|pmvnzb|pmvlzb|pmvgezb|pmulhriw|pmachriw)(?-i)\b"
color statement "\b(?i)(femms|pavgusb|pf2id|pfacc|pfadd|pfcmpeq|pfcmpge|pfcmpgt|pfmax|pfmin|pfmul|pfrcp|pfrcpit1|pfrcpit2|pfrsqit1|pfrsqrt|pfsub|pfsubr|pi2fd|pmulhrw|prefetch|prefetchw)(?-i)\b"
color statement "\b(?i)(pf2iw|pfnacc|pfpnacc|pi2fw|pswapd)(?-i)\b"
color statement "\b(?i)(pfrsqrtv|pfrcpv)(?-i)\b"
color statement "\b(?i)(addps|addss|cmpps|cmpss|comiss|cvtpi2ps|cvtps2pi|cvtsi2ss|cvtss2si|cvttps2pi|cvttss2si|divps|divss|ldmxcsr|maxps|maxss|minps|minss|movaps|movhlps|movhps|movlhps|movlps|movmskps|movntps|movss|movups|mulps|mulss|rcpps|rcpss|rsqrtps|rsqrtss|shufps|sqrtps|sqrtss|stmxcsr|subps|subss|ucomiss|unpckhps|unpcklps)(?-i)\b"
color statement "\b(?i)(andnps|andps|orps|pavgb|pavgw|pextrw|pinsrw|pmaxsw|pmaxub|pminsw|pminub|pmovmskb|pmulhuw|psadbw|pshufw|xorps)(?-i)\b"
color statement "\b(?i)(movups|movss|movlps|movhlps|movlps|unpcklps|unpckhps|movhps|movlhps|prefetchnta|prefetch0|prefetch1|prefetch2|nop|movaps|cvtpi2ps|cvtsi2ss|cvtps2pi|cvttss2si|cvtps2pi|cvtss2si|ucomiss|comiss|sqrtps|sqrtss|rsqrtps|rsqrtss|rcpps|andps|orps|xorps|addps|addss|mulps|mulss|subps|subss|minps|minss|divps|divss|maxps|maxss|pshufw|ldmxcsr|stmxcsr|sfence|cmpps|cmpss|pinsrw|pextrw|shufps|pmovmskb|pminub|pmaxub|pavgb|pavgw|pmulhuw|movntq|pminsw|pmaxsw|psadbw|maskmovq)(?-i)\b"
color statement "\b(?i)(addpd|addsd|addnpd|cmppd|cmpsd)(?-i)\b"
color statement "\b(?i)(addpd|addsd|andnpd|andpd|cmppd|cmpsd|comisd|cvtdq2pd|cvtdq2ps|cvtpd2dq|cvtpd2pi|cvtpd2ps|cvtpi2pd|cvtps2dq|cvtps2pd|cvtsd2si|cvtsd2ss|cvtsi2sd|cvtss2sd|cvttpd2dq|cvttpd2pi|cvttps2dq|cvttsd2si|divpd|divsd|maxpd|maxsd|minpd|minsd|movapd|movhpd|movlpd|movmskpd|movsd|movupd|mulpd|mulsd|orpd|shufpd|sqrtpd|sqrtsd|subpd|subsd|ucomisd|unpckhpd|unpcklpd|xorpd)(?-i)\b"
color statement "\b(?i)(movdq2q|movdqa|movdqu|movq2dq|paddq|psubq|pmuludq|pshufhw|pshuflw|pshufd|pslldq|psrldq|punpckhqdq|punpcklqdq)(?-i)\b"
color statement "\b(?i)(addsubpd|addsubps|haddpd|haddps|hsubpd|hsubps|movddup|movshdup|movsldu)(?-i)\b"
color statement "\b(?i)(lddqu)(?-i)\b"
color statement "\b(?i)(psignw|psignd|psignb|pshufb|pmulhrsw|pmaddubsw|phsubw|phsubsw|phsubd|phaddw|phaddsw|phaddd|palignr|pabsw|pabsd|pabsb)(?-i)\b"
color statement "\b(?i)(dpps|dppd|blendps|blendpd|blendvps|blendvpd|roundps|roundss|roundpd|roundsd|insertps|extractps)(?-i)\b"
color statement "\b(?i)(mpsadbw|phminposuw|pmulld|pmuldq|pblendvb|pblendw|pminsb|pmaxsb|pminuw|pmaxuw|pminud|pmaxud|pminsd|pmaxsd|pinsrb|pinsrd/pinsrq|pextrb|pextrw|pextrd/pextrq|pmovsxbw|pmovzxbw|pmovsxbd|pmovzxbd|pmovsxbq|pmovzxbq|pmovsxwd|pmovzxwd|pmovsxwq|pmovzxwq|pmovsxdq|pmovzxdq|ptest|pcmpeqq|packusdw|movntdqa)(?-i)\b"
color statement "\b(?i)(extrq|insertq|movntsd|movntss)(?-i)\b"
color statement "\b(?i)(crc32|pcmpestri|pcmpestrm|pcmpistri|pcmpistrm|pcmpgtq)(?-i)\b"
color statement "\b(?i)(vfmaddpd|vfmaddps|vfmaddsd|vfmaddss|vfmaddsubpd|vfmaddsubps|vfmsubaddpd|vfmsubaddps|vfmsubpd|vfmsubps|vfmsubsd|vfmsubss|vfnmaddpd|vfnmaddps|vfnmaddsd|vfnmaddss|vfnmsubps|vfnmsubsd|vfnmsubss)(?-i)\b"
# Crypto
color statement "\b(?i)(aesenc|aesenclast|aesdec|aesdeclast|aeskeygenassist|aesimc)(?-i)\b"
color statement "\b(?i)(sha1rnds4|sha1nexte|sha1msg1|sha1msg2|sha256rnds2|sha256msg1|sha256msg2)(?-i)\b"
# Undocumented
color statement "\b(?i)(aam|aad|salc|icebp|loadall|loadalld|ud1)(?-i)\b"
## Registers
color identifier "\b(?i)(al|ah|bl|bh|cl|ch|dl|dh|bpl|sil|r8b|r9b|r10b|r11b|dil|spl|r12b|r13b|r14b|r15)(?-i)\b"
color identifier "\b(?i)(cw|sw|tw|fp_ds|fp_opc|fp_ip|fp_dp|fp_cs|cs|ss|ds|es|fs|gs|gdtr|idtr|tr|ldtr|ax|bx|cx|dx|bp|si|r8w|r9w|r10w|r11w|di|sp|r12w|r13w|r14w|r15w|ip)(?-i)\b"
color identifier "\b(?i)(fp_dp|fp_ip|eax|ebx|ecx|edx|ebp|esi|r8d|r9d|r10d|r11d|edi|esp|r12d|r13d|r14d|r15d|eip|eflags|mxcsr)(?-i)\b"
color identifier "\b(?i)(mm0|mm1|mm2|mm3|mm4|mm5|mm6|mm7|rax|rbx|rcx|rdx|rbp|rsi|r8|r9|r10|r11|rdi|rsp|r12|r13|r14|r15|rip|rflags|cr0|cr1|cr2|cr3|cr4|cr5|cr6|cr7|cr8|cr9|cr10|cr11|cr12|cr13|cr14|cr15|msw|dr0|dr1|dr2|dr3|r4|dr5|dr6|dr7|dr8|dr9|dr10|dr11|dr12|dr13|dr14|dr15)(?-i)\b"
color identifier "\b(?i)(st0|st1|st2|st3|st4|st5|st6|st7)(?-i)\b"
color identifier "\b(?i)(xmm0|xmm1|xmm2|xmm3|xmm4|xmm5|xmm6|xmm7|xmm8|xmm9|xmm10|xmm11|xmm12|xmm13|xmm14|xmm15)(?-i)\b"
color identifier "\b(?i)(ymm0|ymm1|ymm2|ymm3|ymm4|ymm5|ymm6|ymm7|ymm8|ymm9|ymm10|ymm11|ymm12|ymm13|ymm14|ymm15)(?-i)\b"
color identifier "\b(?i)(zmm0|zmm1|zmm2|zmm3|zmm4|zmm5|zmm6|zmm7|zmm8|zmm9|zmm10|zmm11|zmm12|zmm13|zmm14|zmm15|zmm16|zmm17|zmm18|zmm19|zmm20|zmm21|zmm22|zmm23|zmm24|zmm25|zmm26|zmm27|zmm28|zmm29|zmm30|zmm31)(?-i)\b"
## Constants
# Number - it works
color constant.number "\b(|h|A|0x)+[0-9]+(|h|A)+\b"
color constant.number "\b0x[0-9 a-f A-F]+\b"
## Preprocessor (NASM)
color preproc "%+(\+|\?|\?\?|)[a-z A-Z 0-9]+"
color preproc "%\[[. a-z A-Z 0-9]*\]"
## Other
color statement "\b(?i)(extern|global|section|segment|_start|\.text|\.data|\.bss)(?-i)\b"
color statement "\b(?i)(db|dw|dd|dq|dt|ddq|do)(?-i)\b"
color identifier "[a-z A-Z 0-9 _]+:"
# String
color constant.string ""(\\.|[^"])*""
color constant.string "'(\\.|[^'])*'"
## Comments
color comment ";.*"

View File

@@ -0,0 +1,13 @@
syntax "caddyfile" "Caddyfile"
color identifier "^\s*\S+(\s|$)"
color type "^([\w.:/-]+,? ?)+[,{]$"
color constant.specialChar "\s{$"
color constant.specialChar "^\s*}$"
color constant.string start="\"" end="\""
color preproc "\{(\w+|\$\w+|%\w+%)\}"
color comment "#.*"
# extra and trailing spaces
color ,red "([[:space:]]{2,}|\t){$"
color ,red "[[:space:]]+$"

View File

@@ -3,8 +3,8 @@
syntax "conf" "\.c[o]?nf$"
## Possible errors and parameters
## Strings
white (i) ""(\\.|[^"])*""
color constant.string (i) ""(\\.|[^"])*""
## Comments
brightblue (i) "^[[:space:]]*#.*$"
cyan (i) "^[[:space:]]*##.*$"
color comment (i) "^[[:space:]]*#.*$"
color comment (i) "^[[:space:]]*##.*$"

View File

@@ -11,6 +11,12 @@ color special "!important"
color identifier ":active|:focus|:hover|:link|:visited|:link|:after|:before|$"
color special "(\{|\}|\(|\)|\;|:|\]|~|<|>|,)"
# SCSS Varaibles
color identifier (i) "\$\{?[0-9A-Z_!@#$*?-]+\}?"
# SCSS Commands
color statement "@import|@mixin|@extend"
# Strings
color constant ""(\\.|[^"])*""
color constant "'(\\.|[^'])*'"

19
runtime/syntax/dart.micro Normal file
View File

@@ -0,0 +1,19 @@
syntax "dart" "\.dart$"
color constant.number "\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\b"
color constant.number "\b[-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([EePp][+-]?[0-9]+)?[fFlL]?"
color constant.number "\b[-+]?([0-9]+[EePp][+-]?[0-9]+)[fFlL]?"
color identifier "[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[(]"
color statement "\b(break|case|catch|continue|default|else|finally)\b"
color statement "\b(for|function|get|if|in|as|is|new|return|set|switch|final|await|async|sync)\b"
color statement "\b(switch|this|throw|try|var|void|while|with|import|library|part|const|export)\b"
color constant "\b(true|false|null)\b"
color type "\b(List|String)\b"
color type "\b(int|num|double|bool)\b"
color statement "[-+/*=<>!~%?:&|]"
color constant "/[^*]([^/]|(\\/))*[^\\]/[gim]*"
color constant "\\[0-7][0-7]?[0-7]?|\\x[0-9a-fA-F]+|\\[bfnrt'"\?\\]"
color comment "(^|[[:space:]])//.*"
color comment "/\*.+\*/"
color todo "TODO:?"
color constant.string ""(\\.|[^"])*"|'(\\.|[^'])*'"

View File

@@ -2,29 +2,27 @@
##
syntax "ebuild" "\.e(build|class)$"
## All the standard portage functions
color brightgreen "^src_(unpack|compile|install|test)" "^pkg_(config|nofetch|setup|(pre|post)(inst|rm))"
color identifier "^src_(unpack|compile|install|test)" "^pkg_(config|nofetch|setup|(pre|post)(inst|rm))"
## Highlight bash related syntax
color green "\<(case|do|done|elif|else|esac|exit|fi|for|function|if|in|local|read|return|select|shift|then|time|until|while|continue|break)\>"
color green "(\{|\}|\(|\)|\;|\]|\[|`|\\|\$|<|>|!|=|&|\|)"
color green "-(e|d|f|r|g|u|w|x|L)\>"
color green "-(eq|ne|gt|lt|ge|le|s|n|z)\>"
color statement "\b(case|do|done|elif|else|esac|exit|fi|for|function|if|in|local|read|return|select|shift|then|time|until|while|continue|break)\b"
color statement "(\{|\}|\(|\)|\;|\]|\[|`|\\|\$|<|>|!|=|&|\|)"
color statement "-(e|d|f|r|g|u|w|x|L)\b"
color statement "-(eq|ne|gt|lt|ge|le|s|n|z)\b"
## Highlight variables ... official portage ones in red, all others in bright red
color brightred "\$\{?[a-zA-Z_0-9]+\}?"
color red "\<(ARCH|HOMEPAGE|DESCRIPTION|IUSE|SRC_URI|LICENSE|SLOT|KEYWORDS|FILESDIR|WORKDIR|(P|R)?DEPEND|PROVIDE|DISTDIR|RESTRICT|USERLAND)\>"
color red "\<(S|D|T|PV|PF|P|PN|A)\>" "\<C(XX)?FLAGS\>" "\<LDFLAGS\>" "\<C(HOST|TARGET|BUILD)\>"
color preproc "\$\{?[a-zA-Z_0-9]+\}?"
color special "\b(ARCH|HOMEPAGE|DESCRIPTION|IUSE|SRC_URI|LICENSE|SLOT|KEYWORDS|FILESDIR|WORKDIR|(P|R)?DEPEND|PROVIDE|DISTDIR|RESTRICT|USERLAND)\b"
color special "\b(S|D|T|PV|PF|P|PN|A)\b" "\bC(XX)?FLAGS\b" "\bLDFLAGS\b" "\bC(HOST|TARGET|BUILD)\b"
## Highlight portage commands
color magenta "\<use(_(with|enable))?\> [!a-zA-Z0-9_+ -]*" "inherit.*"
color brightblue "\<e(begin|end|conf|install|make|warn|infon?|error|log|patch|new(group|user))\>"
color brightblue "\<die\>" "\<use(_(with|enable))?\>" "\<inherit\>" "\<has\>" "\<(has|best)_version\>" "\<unpack\>"
color brightblue "\<(do|new)(ins|s?bin|doc|lib(\.so|\.a)|man|info|exe|initd|confd|envd|pam|menu|icon)\>"
color brightblue "\<do(python|sed|dir|hard|sym|html|jar|mo)\>" "\<keepdir\>"
color brightblue "prepall(docs|info|man|strip)" "prep(info|lib|lib\.(so|a)|man|strip)"
color brightblue "\<(doc|ins|exe)into\>" "\<f(owners|perms)\>" "\<(exe|ins|dir)opts\>"
color identifier "\buse(_(with|enable))?\b [!a-zA-Z0-9_+ -]*" "inherit.*"
color statement "\be(begin|end|conf|install|make|warn|infon?|error|log|patch|new(group|user))\b"
color statement "\bdie\b" "\buse(_(with|enable))?\b" "\binherit\b" "\bhas\b" "\b(has|best)_version\b" "\bunpack\b"
color statement "\b(do|new)(ins|s?bin|doc|lib(\.so|\.a)|man|info|exe|initd|confd|envd|pam|menu|icon)\b"
color statement "\bdo(python|sed|dir|hard|sym|html|jar|mo)\b" "\bkeepdir\b"
color statement "prepall(docs|info|man|strip)" "prep(info|lib|lib\.(so|a)|man|strip)"
color statement "\b(doc|ins|exe)into\b" "\bf(owners|perms)\b" "\b(exe|ins|dir)opts\b"
## Highlight common commands used in ebuilds
color blue "\<make\>" "\<(cat|cd|chmod|chown|cp|echo|env|export|grep|let|ln|mkdir|mv|rm|sed|set|tar|touch|unset)\>"
color type "\bmake\b" "\b(cat|cd|chmod|chown|cp|echo|env|export|grep|let|ln|mkdir|mv|rm|sed|set|tar|touch|unset)\b"
## Highlight comments (doesnt work that well)
color yellow "#.*$"
color comment "#.*$"
## Highlight strings (doesnt work that well)
color brightyellow ""(\\.|[^\"])*"" "'(\\.|[^'])*'"
## Trailing space is bad!
color ,green "[[:space:]]+$"
color constant.string ""(\\.|[^\"])*"" "'(\\.|[^'])*'"

View File

@@ -1,11 +1,9 @@
syntax "ini" "\.(ini|desktop|lfl|override)$" "(mimeapps\.list|pinforc|setup\.cfg)$" "weechat/.+\.conf$"
header "^\[[A-Za-z]+\]$"
color brightcyan "\<(true|false)\>"
color cyan "^[[:space:]]*[^=]*="
color brightmagenta "^[[:space:]]*\[.*\]$"
color red "[=;]"
color yellow ""(\\.|[^"])*"|'(\\.|[^'])*'"
color brightblack "(^|[[:space:]])#([^{].*)?$"
color ,green "[[:space:]]+$"
color ,red " + +| + +"
color constant "\b(true|false)\b"
color identifier "^[[:space:]]*[^=]*="
color special "^[[:space:]]*\[.*\]$"
color statement "[=;]"
color comment "(^|[[:space:]])#([^{].*)?$"
color constant.string ""(\\.|[^"])*"|'(\\.|[^'])*'"

View File

@@ -1,11 +1,13 @@
syntax "json" "\.json$"
header "^\{$"
color blue "\<[-]?[1-9][0-9]*([Ee][+-]?[0-9]+)?\>" "\<[-]?[0](\.[0-9]+)?\>"
color cyan "\<null\>"
color brightcyan "\<(true|false)\>"
color yellow ""(\\.|[^"])*"|'(\\.|[^'])*'"
color brightyellow "\"(\\"|[^"])*\"[[:space:]]*:" "'(\'|[^'])*'[[:space:]]*:"
color magenta "\\u[0-9a-fA-F]{4}|\\[bfnrt'"/\\]"
color constant.number "\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\b"
color constant.number "\b[-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([EePp][+-]?[0-9]+)?[fFlL]?"
color constant.number "\b[-+]?([0-9]+[EePp][+-]?[0-9]+)[fFlL]?"
color constant "\b(null)\b"
color constant "\b(true|false)\b"
color constant.string ""(\\.|[^"])*"|'(\\.|[^'])*'"
color statement "\"(\\"|[^"])*\"[[:space:]]*:" "'(\'|[^'])*'[[:space:]]*:"
color constant "\\u[0-9a-fA-F]{4}|\\[bfnrt'"/\\]"
color ,green "[[:space:]]+$"
color ,red " + +| + +"

21
runtime/syntax/lfe.micro Normal file
View File

@@ -0,0 +1,21 @@
syntax "lfe" "lfe$" "\.lfe$"
# Parens are everywhere!
color statement "\("
color statement "\)"
# Good overrides for LFE in particular
color type "defun|define-syntax|define|defmacro|defmodule|export"
# Dirty base cases stolen from the generic lisp syntax
color constant "\ [A-Za-z][A-Za-z0-9_-]+\ "
color statement "\(([-+*/<>]|<=|>=)|'"
color constant.number "\<[0-9]+\>"
color constant.string "\"(\\.|[^"])*\""
color special "['|`][A-Za-z][A-Za-z0-9_-]+"
color constant.string "\\.?"
color comment "(^|[[:space:]]);.*"
# Some warning colors because our indents are wrong.
color ,green "[[:space:]]+$"
color ,red " + +| + +"

View File

@@ -0,0 +1,10 @@
# Micro syntax by <nickolay02@inbox.ru>
syntax "micro" "\.(micro)$"
color statement "\b(syntax|color|color-link)\b"
color statement "\b(start=|end=)\b"
color identifier "\b(default|comment|identifier|constant|constant|string|constant|number|statement|preproc|type|special|underlined|error|todo|statusline|indent-char|line=number|gutter-error|gutter-warning|cursor-line)\b"
color constant.number "\b(|h|A|0x)+[0-9]+(|h|A)+\b"
color constant.number "\b0x[0-9 a-f A-F]+\b"
color constant.string ""(\\.|[^"])*""
color comment "#.*"

View File

@@ -0,0 +1,24 @@
syntax "pascal" "\.pas$"
# color identifier "\b[\pL_][\pL_\pN]*\b"
color comment "//.*"
color comment start="\(\*" end="\*\)"
color comment start="({)(?:[^$])" end="}"
color special start="asm" end="end"
color type "\b(?i:(string|ansistring|widestring|shortstring|char|ansichar|widechar|boolean|byte|shortint|word|smallint|longword|cardinal|longint|integer|int64|single|currency|double|extended))\b"
color statement "\b(?i:(and|asm|array|begin|break|case|const|constructor|continue|destructor|div|do|downto|else|end|file|for|function|goto|if|implementation|in|inline|interface|label|mod|not|object|of|on|operator|or|packed|procedure|program|record|repeat|resourcestring|set|shl|shr|then|to|type|unit|until|uses|var|while|with|xor))\b"
color statement "\b(?i:(as|class|dispose|except|exit|exports|finalization|finally|inherited|initialization|is|library|new|on|out|property|raise|self|threadvar|try))\b"
color statement "\b(?i:(absolute|abstract|alias|assembler|cdecl|cppdecl|default|export|external|forward|generic|index|local|name|nostackframe|oldfpccall|override|pascal|private|protected|public|published|read|register|reintroduce|safecall|softfloat|specialize|stdcall|virtual|write))\b"
color constant "\b(?i:(false|true|nil))\b"
color constant "\$[0-9A-Fa-f]+" "\b[+-]?[0-9]+([.]?[0-9]+)?(?i:e[+-]?[0-9]+)?"
color constant.string "'(?:[^']+|'')*'"
color preproc start="{\$" end="}"

View File

@@ -1,40 +1,30 @@
## PHP Syntax Highlighting
syntax "php" "\.php[2345s~]?$"
color white start="<\?(php|=)?" end="\?>"
# Functions
color brightblue "([a-zA-Z0-9_-]*)\("
# Constructs
color brightblue "(class|extends|goto) ([a-zA-Z0-9_]*)"
color green "[^a-z0-9_-]{1}(var|class|function|echo|case|break|default|exit|switch|if|else|elseif|endif|foreach|endforeach|@|while|public|private|protected|return|true|false|null|TRUE|FALSE|NULL|const|static|extends|as|array|require|include|require_once|include_once|define|do|continue|declare|goto|print|in|namespace|use)[^a-z0-9_-]{1}"
color brightblue "[a-zA-Z0-9]+:"
# Variables
color white "\$[a-zA-Z_0-9$]*|[=!<>]"
color white "\->[a-zA-Z_0-9$]*|[=!<>]"
# Special Characters
color yellow "[.,{}();]"
color yellow "\["
color yellow "\]"
color yellow "[=][^>]"
# Numbers
color magenta "[+-]*([0-9]\.)*[0-9]+([eE][+-]?([0-9]\.)*[0-9])*"
color magenta "0x[0-9a-zA-Z]*"
# Special Variables
color brightblue "(\$this|parent::|self::|\$this->)"
# Bitwise Operations
color magenta "(\;|\||\^){1}"
# And/Or/SRO/etc
color green "(\;\;|\|\||::|=>|->)"
# Online Comments
color brightyellow "(#.*|//.*)$"
# STRINGS!
color red "('[^']*')|(\"[^\"]*\")"
# Inline Variables
color white "\{\$[^}]*\}"
# PHP Tags
color red "(<\?(php)?|\?>)"
# General HTML
color red start="\?>" end="<\?(php|=)?"
# trailing whitespace
color ,green "[^[:space:]]{1}[[:space:]]+$"
# multi-line comments
color brightyellow start="/\*" end="\*/"
color default start="<\?(php|=)?" end="\?>"
color special "([a-zA-Z0-9_-]+)\("
color identifier "(var|class|goto|extends|function|echo|case|break|default|exit|switch|foreach|endforeach|while|const|static|extends|as|require|include|require_once|include_once|define|do|continue|declare|goto|print|in|trait|interface|[E|e]xception|array|int|string|bool|iterable|void)[\s|\)]"
color identifier "[a-zA-Z\\]+::"
color identifier "new\s([a-zA-Z0-9\\]+)"
color identifier "([A-Z][a-zA-Z0-9_]+)\s"
color identifier "([A-Z0-9_]+)[;|\s|\)|,]"
color statement "(implements|abstract|global|public|instanceof|private|protected|static|if|else|elseif|endif|namespace|use|as|new|throw|catch|try|return)[\s|;]"
color constant "(true|false|null|TRUE|FALSE|NULL)"
color constant "[\s|=|>|\s|\(|/|+|-|\*|\[](\d+)"
color identifier "(\$this|parent|self|\$this->)"
color statement "(=>|===|!==|==|!=|&&|\|\||::|=|->|\!)"
color default "(\$[a-zA-Z0-9\-_]+)"
color default "[\(|\)|/|+|-|\*|\[|,|;]"
color constant.string "('.*?'|\".*?\")"
color comment start="/\*" end="\*/"
color comment "(#.*|//.*)$"

View File

@@ -1,4 +1,4 @@
syntax "shell" "\.sh$" "\.bash" "\.bashrc" "bashrc" "\.bash_aliases" "bash_aliases" "\.bash_functions" "bash_functions" "\.bash_profile" "bash_profile" "Pkgfile" "PKGBUILD" ".ebuild\$" "APKBUILD"
syntax "shell" "\.sh$" "\.bash" "\.bashrc" "bashrc" "\.bash_aliases" "bash_aliases" "\.bash_functions" "bash_functions" "\.bash_profile" "bash_profile" "Pkgfile" "pkgmk.conf" "profile" "rc.conf" "PKGBUILD" ".ebuild\$" "APKBUILD"
header "^#!.*/(env +)?(ba)?sh( |$)"
# Numbers

View File

@@ -0,0 +1,20 @@
syntax "typescript" "\.ts$"
color constant.number "\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\b"
color constant.number "\b[-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([EePp][+-]?[0-9]+)?[fFlL]?"
color constant.number "\b[-+]?([0-9]+[EePp][+-]?[0-9]+)[fFlL]?"
color identifier "[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[(]"
color statement "\b(break|case|catch|continue|default|delete|do|else|finally)\b"
color statement "\b(declare|interface|import|export|from|for|function|get|if|in|instanceof|new|return|set|switch)\b"
color statement "\b(switch|this|throw|try|typeof|var|void|while|with|async|await)\b"
color constant "\b(null|undefined|NaN)\b"
color constant "\b(true|false)\b"
color type "\b(Array|Boolean|Date|Enumerator|Error|Function|Math|string|number|boolean|any)\b"
color type "\b(Number|Object|RegExp|String)\b"
color statement "[-+/*=<>!~%?:&|]"
color constant "/[^*]([^/]|(\\/))*[^\\]/[gim]*"
color constant "\\[0-7][0-7]?[0-7]?|\\x[0-9a-fA-F]+|\\[bfnrt'"\?\\]"
color comment "(^|[[:space:]])//.*"
color comment "/\*.+\*/"
color todo "TODO:?"
color constant.string ""(\\.|[^"])*"|'(\\.|[^'])*'"

View File

@@ -1,13 +1,11 @@
syntax "yaml" "\.ya?ml$"
header "^---" "%YAML"
color green "(^| )!!(binary|bool|float|int|map|null|omap|seq|set|str) "
color brightcyan "\<(YES|yes|Y|y|ON|on|NO|no|N|n|OFF|off)\>"
color brightcyan "\<(true|false)\>"
color red ":[[:space:]]" "\[" "\]" ":[[:space:]]+[|>]" "^[[:space:]]*- "
color brightyellow "[[:space:]][\*&][A-Za-z0-9]+"
color yellow ""(\\.|[^"])*"|'(\\.|[^'])*'"
color brightblack "(^|[[:space:]])#([^{].*)?$"
color brightmagenta "^---" "^\.\.\." "^%YAML" "^%TAG"
color ,green "[[:space:]]+$"
color ,red " + +| + +"
color type "(^| )!!(binary|bool|float|int|map|null|omap|seq|set|str) "
color constant "\b(YES|yes|Y|y|ON|on|NO|no|N|n|OFF|off)\b"
color constant "\b(true|false)\b"
color statement ":[[:space:]]" "\[" "\]" ":[[:space:]]+[|>]" "^[[:space:]]*- "
color identifier "[[:space:]][\*&][A-Za-z0-9]+"
color constant.string ""(\\.|[^"])*"|'(\\.|[^'])*'"
color comment "(^|[[:space:]])#([^{].*)?$"
color special "^---" "^\.\.\." "^%YAML" "^%TAG"

10
tools/build-date.go Normal file
View File

@@ -0,0 +1,10 @@
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println(time.Now().Local().Format("January 02, 2006"))
}