mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-31 07:07:09 +09:00
Compare commits
100 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fc8f847a6 | ||
|
|
af6ef4f87f | ||
|
|
7f287b62fb | ||
|
|
36d72c4cab | ||
|
|
71ee185b80 | ||
|
|
0360a2fcb5 | ||
|
|
2ee7adb196 | ||
|
|
d247db3e9d | ||
|
|
e4c2f5d259 | ||
|
|
cc15df9307 | ||
|
|
812b547679 | ||
|
|
1c43bb572a | ||
|
|
f96e9e9c1d | ||
|
|
7dfeda1ae5 | ||
|
|
d6ccaf0e41 | ||
|
|
6b6fcc8ba0 | ||
|
|
07bfcc9747 | ||
|
|
423f4675d2 | ||
|
|
c01ba97215 | ||
|
|
288717451f | ||
|
|
a1f3499825 | ||
|
|
63fa8fec41 | ||
|
|
b9e916999f | ||
|
|
afedad9977 | ||
|
|
d82ea2279d | ||
|
|
5b5998cf14 | ||
|
|
7b6430af1c | ||
|
|
a0d475bebf | ||
|
|
31cd4b5795 | ||
|
|
19ee4b281e | ||
|
|
a171795654 | ||
|
|
98d8bfa879 | ||
|
|
7bc2d870cd | ||
|
|
678819683a | ||
|
|
08e46f9112 | ||
|
|
e071209add | ||
|
|
74e79dc8f2 | ||
|
|
955e8ffb08 | ||
|
|
b87a74711e | ||
|
|
ade0e9dd39 | ||
|
|
f05f0b06ac | ||
|
|
f2006f592a | ||
|
|
5e66489836 | ||
|
|
9daa05d696 | ||
|
|
d76704839a | ||
|
|
329669ce79 | ||
|
|
5af5140362 | ||
|
|
bf6ce3a17e | ||
|
|
e99fd1337e | ||
|
|
17dac164ea | ||
|
|
b7c99c52d2 | ||
|
|
278aa6b050 | ||
|
|
773c54a40d | ||
|
|
74589af1fc | ||
|
|
f01ad3f726 | ||
|
|
a0f3ec805d | ||
|
|
ea6012922f | ||
|
|
da33b59858 | ||
|
|
9703d4f52f | ||
|
|
f3a30412f4 | ||
|
|
3116b082d8 | ||
|
|
3e0a1b4517 | ||
|
|
ac3de065d9 | ||
|
|
3e63ec74b9 | ||
|
|
c7334eb3b7 | ||
|
|
dfbddd4b86 | ||
|
|
299416062f | ||
|
|
8b8fffb98d | ||
|
|
ec221c0bc4 | ||
|
|
d27f8f9802 | ||
|
|
c40c79427a | ||
|
|
8a4f2193d8 | ||
|
|
aa667f6ba9 | ||
|
|
d067de8150 | ||
|
|
b3559df543 | ||
|
|
f4e94d6d34 | ||
|
|
13daa4e715 | ||
|
|
75be4f5f61 | ||
|
|
46ced988eb | ||
|
|
28acfc6d3f | ||
|
|
660c7d3be5 | ||
|
|
52617bd5a8 | ||
|
|
9db181037f | ||
|
|
861ea5aabc | ||
|
|
e4125c0c6a | ||
|
|
ff9a8a1247 | ||
|
|
ac29e30f54 | ||
|
|
e7facd74ba | ||
|
|
e6797e0303 | ||
|
|
6041e063e2 | ||
|
|
c3861955e0 | ||
|
|
4a45e69eb1 | ||
|
|
e52d05113e | ||
|
|
45992a0e0a | ||
|
|
1fb405afd3 | ||
|
|
e23d4d8fa1 | ||
|
|
d8aab386f1 | ||
|
|
7d422bfae2 | ||
|
|
7bc870e72f | ||
|
|
edee53f6f2 |
7
.editorconfig
Normal file
7
.editorconfig
Normal file
@@ -0,0 +1,7 @@
|
||||
# See http://editorconfig.org
|
||||
|
||||
# In Go files we indent with tabs but still
|
||||
# set indent_size to control the GitHub web viewer.
|
||||
[*.go]
|
||||
indent_size=4
|
||||
|
||||
26
README.md
26
README.md
@@ -69,7 +69,19 @@ 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`.
|
||||
|
||||
### Package Managers
|
||||
### Installation script
|
||||
|
||||
There is a great script which can install micro for you by downloading the latest prebuilt binary. You can find it at https://getmic.ro (the github repo for it is [here](https://github.com/benweissmann/getmic.ro)).
|
||||
|
||||
Then you can easily install micro:
|
||||
|
||||
$ curl https://getmic.ro | bash
|
||||
|
||||
The script will install the micro binary to the current directory.
|
||||
|
||||
See the [Github page](https://github.com/benweissmann/getmic.ro) for more information.
|
||||
|
||||
### Package managers
|
||||
|
||||
You can install micro using Homebrew on Mac:
|
||||
|
||||
@@ -92,14 +104,20 @@ scoop install micro
|
||||
On Linux, you can install micro through [snap](https://snapcraft.io/docs/core/install)
|
||||
|
||||
```
|
||||
snap install micro --edge --classic
|
||||
snap install micro --classic
|
||||
```
|
||||
|
||||
On OpenBSD, micro is available in the ports tree. It is also available as a binary package.
|
||||
|
||||
```
|
||||
pkg_add -v micro
|
||||
```
|
||||
|
||||
### Building from source
|
||||
|
||||
If your operating system does not have a binary release, but does run Go, you can build from source.
|
||||
|
||||
Make sure that you have Go version 1.5 or greater (Go 1.4 will work if your version supports CGO) and that your `GOPATH` env variable is set (I recommand setting it to `~/go` if you don't have one).
|
||||
Make sure that you have Go version 1.5 or greater (Go 1.4 will work if your version supports CGO) and that your `GOPATH` env variable is set (I recommend setting it to `~/go` if you don't have one).
|
||||
|
||||
```
|
||||
go get -d github.com/zyedidia/micro/cmd/micro
|
||||
@@ -115,7 +133,7 @@ You can install directly with `go get` (`go get -u github.com/zyedidia/micro/cmd
|
||||
|
||||
### MacOS terminal
|
||||
|
||||
If you are using MacOS, you should consider using [iTerm2](http://iterm2.com/) instead of the default Mac terminal. The iTerm2 terminal has much better mouse support as well as better handling of key events. The newest versions also support true color.
|
||||
If you are using MacOS, you should consider using [iTerm2](http://iterm2.com/) instead of the default Mac terminal. The iTerm2 terminal has much better mouse support as well as better handling of key events. For best keybinding behavior, choose `xterm defaults` under `Preferences->Profiles->Keys->Load Preset`. The newest versions also support true color.
|
||||
|
||||
### Linux clipboard support
|
||||
|
||||
|
||||
63
assets/logo.svg
Normal file
63
assets/logo.svg
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="svg3336"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
width="128"
|
||||
height="128"
|
||||
viewBox="0 0 128 128"
|
||||
sodipodi:docname="logo.svg">
|
||||
<metadata
|
||||
id="metadata3342">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs3340" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1355"
|
||||
inkscape:window-height="717"
|
||||
id="namedview3338"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.6243169"
|
||||
inkscape:cx="111.32302"
|
||||
inkscape:cy="30.538264"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg3336" />
|
||||
<path
|
||||
style="fill:#2e3192;fill-opacity:1"
|
||||
d="m 56.1,127.32358 c -13.68932,-1.70993 -27.156628,-8.3544 -37.112903,-18.31068 -25.0687936,-25.068788 -25.0687936,-65.95701 0,-91.025803 25.068793,-25.0687936 65.957015,-25.0687936 91.025803,0 25.0688,25.068793 25.0688,65.957015 0,91.025803 C 95.87457,123.15123 76.198116,129.83404 56.1,127.32358 Z"
|
||||
id="path3364"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
d="m 40.756452,106.01908 c 1.442831,-1.83426 1.55476,-4.09687 0.414499,-8.37899 -0.678184,-2.546844 -0.684604,-4.05591 -0.03829,-9 1.276867,-9.767604 4.483143,-23.040636 5.565559,-23.039766 0.220979,1.74e-4 0.417725,2.092674 0.437213,4.65 0.04167,5.468298 1.558564,9.06891 4.638769,11.010942 2.551646,1.608774 9.15365,1.329324 12.80399,-0.541974 3.245124,-1.663572 7.649064,-6.112434 9.850956,-9.951438 L 76.188736,67.7 l 0.0054,3.922866 c 0.0042,2.867148 0.36894,4.642788 1.355628,6.59796 1.532058,3.035856 3.323226,4.15755 6.659322,4.17033 5.192928,0.01986 9.07014,-3.668676 10.866768,-10.338036 0.98277,-3.64821 1.064448,-11.21265 0.09235,-8.55312 -3.025218,8.276592 -4.468212,9.893562 -9.238056,10.351884 -2.629152,0.25263 -3.177804,0.08883 -4.921776,-1.469412 -1.609044,-1.437678 -2.016072,-2.308416 -2.258508,-4.8315 -0.262884,-2.73585 0.105942,-4.06497 3.32007,-11.964365 C 88.28388,40.315087 89.33625,35.536248 87,33.2 c -1.559352,-1.559353 -3.62787,-1.522741 -5.691792,0.10074 -2.295762,1.805846 -3.105984,4.070756 -5.14293,14.376662 -2.464164,12.46744 -6.525822,20.297092 -12.62193,24.331306 C 59.052142,74.98085 52.704914,73.6403 50.637191,69.282896 49.19967,66.253544 49.857706,62.552972 53.387813,53.814319 56.613526,45.829186 58.8,38.711369 58.8,36.195564 c 0,-4.161283 -4.366993,-5.665719 -7.364438,-2.537061 -2.183558,2.279144 -3.117251,5.256959 -4.280897,13.653016 -0.547956,3.953665 -1.259292,9.010489 -1.580746,11.237387 -0.321454,2.226896 -2.083918,8.706896 -3.916587,14.400002 -4.33165,13.456074 -6.85029,23.184822 -7.273674,28.096022 -0.325586,3.77675 -0.269352,4.00056 1.319044,5.25 2.187498,1.72068 3.541408,1.64679 5.05375,-0.27585 z"
|
||||
id="path3362"
|
||||
inkscape:connector-curvature="0" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
56
assets/packaging/micro.1
Normal file
56
assets/packaging/micro.1
Normal file
@@ -0,0 +1,56 @@
|
||||
.\" micro manual page - micro(1)
|
||||
.\"
|
||||
.\" Copyright © 2017 Zachary Yedidia <zyedidia@gmail.com>
|
||||
.\" Copyright © 2017 Collin Warren <anatoly@somethinghub.com>
|
||||
.\"
|
||||
.\" This document is provided under the same licensing as micro.
|
||||
.\" See \usr\share\doc\micro\LICENSE for more information.
|
||||
.TH micro 1 "2017-03-28"
|
||||
.SH NAME
|
||||
micro \- An intuitive and modern terminal text editor
|
||||
.
|
||||
.SH SYNOPSIS
|
||||
.B micro
|
||||
.RB []
|
||||
[
|
||||
.I "filename \&..."
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
( Copied from the README file. )
|
||||
|
||||
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. It comes as one single, batteries-included, static binary with no dependencies.
|
||||
|
||||
As the name indicates, micro aims to be somewhat of a successor to the nano editor by being easy to install and use in a pinch, but micro also aims to be
|
||||
enjoyable to use full time, whether you work in the terminal because you prefer it (like me), or because you need to (over ssh).
|
||||
|
||||
.SH OPTIONS
|
||||
.B \-v --version
|
||||
Displays the current version of micro and the git commit hash.
|
||||
.TP
|
||||
.SH ENVIRONMENT
|
||||
Micro's behaviour can be changed by setting environment variables, of which
|
||||
there is currently only one:
|
||||
.I MICRO_TRUE_COLOR
|
||||
|
||||
When MICRO_TRUE_COLOR is set to 1, micro will attempt to treat your terminal as
|
||||
a true-color terminal and will be able to make full use of the true-color colorschemes
|
||||
that are included with micro. If MICRO_TRUE_COLOR is not set or is set to 0, then
|
||||
micro will only make use of 256 color features and will internally map true-color
|
||||
colorschemes to the nearest colors available. For more information see micro's documentation.
|
||||
|
||||
.SH NOTICE
|
||||
This manpage is intended only to serve as a quick guide to the invocation of
|
||||
micro and is not intended to replace the full documentation included with micro
|
||||
which can be accessed from within micro. Micro tells you what key combination to
|
||||
press to get help in the lower right.
|
||||
|
||||
.SH BUGS
|
||||
A comprehensive list of bugs will not be listed in this manpage. See the Github
|
||||
page at \fBhttps://github.com/zyedidia/micro/issues\fP for a list of known bugs
|
||||
and to report any newly encountered bugs you may find. We strive to correct
|
||||
bugs as swiftly as possible.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2017 Zachary Yedidia, Collin Warren, et al.
|
||||
See /usr/share/doc/micro/LICENSE and /usr/share/doc/micro/AUTHORS for more information.
|
||||
15
assets/packaging/micro.desktop
Normal file
15
assets/packaging/micro.desktop
Normal file
@@ -0,0 +1,15 @@
|
||||
[Desktop Entry]
|
||||
|
||||
Name=Micro
|
||||
GenericName=Text Editor
|
||||
Comment=Edit text files in a terminal
|
||||
|
||||
Icon=micro
|
||||
Type=Application
|
||||
Categories=terminal;TextEditor;
|
||||
Keywords=text;editor;syntax;terminal;
|
||||
|
||||
Exec=micro %U
|
||||
StartupNotify=false
|
||||
Terminal=true
|
||||
MimeType=text/plain;text/x-chdr;text/x-csrc;text/x-c++hdr;text/x-c++src;text/x-java;text/x-dsrc;text/x-pascal;text/x-perl;text/x-python;application/x-php;application/x-httpd-php3;application/x-httpd-php4;application/x-httpd-php5;application/xml;text/html;text/css;text/x-sql;text/x-diff;
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/yuin/gopher-lua"
|
||||
"github.com/zyedidia/clipboard"
|
||||
"github.com/zyedidia/micro/cmd/micro/shellwords"
|
||||
"github.com/zyedidia/tcell"
|
||||
)
|
||||
|
||||
@@ -493,6 +494,89 @@ func (v *View) SelectToEndOfLine(usePlugin bool) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// ParagraphPrevious moves the cursor to the previous empty line, or beginning of the buffer if there's none
|
||||
func (v *View) ParagraphPrevious(usePlugin bool) bool {
|
||||
if usePlugin && !PreActionCall("ParagraphPrevious", v) {
|
||||
return false
|
||||
}
|
||||
var line int
|
||||
for line = v.Cursor.Y; line > 0; line-- {
|
||||
if len(v.Buf.lines[line].data) == 0 && line != v.Cursor.Y {
|
||||
v.Cursor.X = 0
|
||||
v.Cursor.Y = line
|
||||
break
|
||||
}
|
||||
}
|
||||
// If no empty line found. move cursor to end of buffer
|
||||
if line == 0 {
|
||||
v.Cursor.Loc = v.Buf.Start()
|
||||
}
|
||||
|
||||
if usePlugin {
|
||||
return PostActionCall("ParagraphPrevious", v)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ParagraphNext moves the cursor to the next empty line, or end of the buffer if there's none
|
||||
func (v *View) ParagraphNext(usePlugin bool) bool {
|
||||
if usePlugin && !PreActionCall("ParagraphNext", v) {
|
||||
return false
|
||||
}
|
||||
|
||||
var line int
|
||||
for line = v.Cursor.Y; line < len(v.Buf.lines); line++ {
|
||||
if len(v.Buf.lines[line].data) == 0 && line != v.Cursor.Y {
|
||||
v.Cursor.X = 0
|
||||
v.Cursor.Y = line
|
||||
break
|
||||
}
|
||||
}
|
||||
// If no empty line found. move cursor to end of buffer
|
||||
if line == len(v.Buf.lines) {
|
||||
v.Cursor.Loc = v.Buf.End()
|
||||
}
|
||||
|
||||
if usePlugin {
|
||||
return PostActionCall("ParagraphNext", v)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (v *View) Retab(usePlugin bool) bool {
|
||||
if usePlugin && !PreActionCall("Retab", v) {
|
||||
return false
|
||||
}
|
||||
|
||||
toSpaces := v.Buf.Settings["tabstospaces"].(bool)
|
||||
tabsize := int(v.Buf.Settings["tabsize"].(float64))
|
||||
dirty := false
|
||||
|
||||
for i := 0; i < v.Buf.NumLines; i++ {
|
||||
l := v.Buf.Line(i)
|
||||
|
||||
ws := GetLeadingWhitespace(l)
|
||||
if ws != "" {
|
||||
if toSpaces {
|
||||
ws = strings.Replace(ws, "\t", Spaces(tabsize), -1)
|
||||
} else {
|
||||
ws = strings.Replace(ws, Spaces(tabsize), "\t", -1)
|
||||
}
|
||||
}
|
||||
|
||||
l = strings.TrimLeft(l, " \t")
|
||||
v.Buf.lines[i].data = []byte(ws + l)
|
||||
dirty = true
|
||||
}
|
||||
|
||||
v.Buf.IsModified = dirty
|
||||
|
||||
if usePlugin {
|
||||
return PostActionCall("Retab", v)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// CursorStart moves the cursor to the start of the buffer
|
||||
func (v *View) CursorStart(usePlugin bool) bool {
|
||||
if usePlugin && !PreActionCall("CursorStart", v) {
|
||||
@@ -914,7 +998,12 @@ func (v *View) SaveAs(usePlugin bool) bool {
|
||||
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), " ")
|
||||
args, err := shellwords.Split(filename)
|
||||
filename = strings.Join(args, " ")
|
||||
if err != nil {
|
||||
messenger.Error("Error parsing arguments: ", err)
|
||||
return false
|
||||
}
|
||||
v.saveToFile(filename)
|
||||
}
|
||||
|
||||
@@ -1551,6 +1640,25 @@ func (v *View) ToggleHelp(usePlugin bool) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// ToggleKeyMenu toggles the keymenu option and resizes all tabs
|
||||
func (v *View) ToggleKeyMenu(usePlugin bool) bool {
|
||||
if v.mainCursor() {
|
||||
if usePlugin && !PreActionCall("ToggleBindings", v) {
|
||||
return false
|
||||
}
|
||||
|
||||
globalSettings["keymenu"] = !globalSettings["keymenu"].(bool)
|
||||
for _, tab := range tabs {
|
||||
tab.Resize()
|
||||
}
|
||||
|
||||
if usePlugin {
|
||||
return PostActionCall("ToggleBindings", v)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ShellMode opens a terminal to run a shell command
|
||||
func (v *View) ShellMode(usePlugin bool) bool {
|
||||
if v.mainCursor() {
|
||||
@@ -1640,6 +1748,7 @@ func (v *View) Quit(usePlugin bool) bool {
|
||||
}
|
||||
|
||||
screen.Fini()
|
||||
messenger.SaveHistory()
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
@@ -1683,6 +1792,7 @@ func (v *View) QuitAll(usePlugin bool) bool {
|
||||
}
|
||||
|
||||
screen.Fini()
|
||||
messenger.SaveHistory()
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,6 +181,13 @@ func OptionValueComplete(inputOpt, input string) (string, []string) {
|
||||
if strings.HasPrefix("dos", input) {
|
||||
suggestions = append(suggestions, "dos")
|
||||
}
|
||||
case "sucmd":
|
||||
if strings.HasPrefix("sudo", input) {
|
||||
suggestions = append(suggestions, "sudo")
|
||||
}
|
||||
if strings.HasPrefix("doas", input) {
|
||||
suggestions = append(suggestions, "doas")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
var bindings map[Key][]func(*View, bool) bool
|
||||
var mouseBindings map[Key][]func(*View, bool, *tcell.EventMouse) bool
|
||||
var helpBinding string
|
||||
var kmenuBinding string
|
||||
|
||||
var mouseBindingActions = map[string]func(*View, bool, *tcell.EventMouse) bool{
|
||||
"MousePress": (*View).MousePress,
|
||||
@@ -41,6 +42,8 @@ var bindingActions = map[string]func(*View, bool) bool{
|
||||
"DeleteWordLeft": (*View).DeleteWordLeft,
|
||||
"SelectToStartOfLine": (*View).SelectToStartOfLine,
|
||||
"SelectToEndOfLine": (*View).SelectToEndOfLine,
|
||||
"ParagraphPrevious": (*View).ParagraphPrevious,
|
||||
"ParagraphNext": (*View).ParagraphNext,
|
||||
"InsertNewline": (*View).InsertNewline,
|
||||
"InsertSpace": (*View).InsertSpace,
|
||||
"Backspace": (*View).Backspace,
|
||||
@@ -78,6 +81,7 @@ var bindingActions = map[string]func(*View, bool) bool{
|
||||
"StartOfLine": (*View).StartOfLine,
|
||||
"EndOfLine": (*View).EndOfLine,
|
||||
"ToggleHelp": (*View).ToggleHelp,
|
||||
"ToggleKeyMenu": (*View).ToggleKeyMenu,
|
||||
"ToggleRuler": (*View).ToggleRuler,
|
||||
"JumpLine": (*View).JumpLine,
|
||||
"ClearStatus": (*View).ClearStatus,
|
||||
@@ -256,6 +260,7 @@ type Key struct {
|
||||
modifiers tcell.ModMask
|
||||
buttons tcell.ButtonMask
|
||||
r rune
|
||||
escape string
|
||||
}
|
||||
|
||||
// InitBindings initializes the keybindings for micro
|
||||
@@ -312,6 +317,14 @@ modSearch:
|
||||
case strings.HasPrefix(k, "Shift"):
|
||||
k = k[5:]
|
||||
modifiers |= tcell.ModShift
|
||||
case strings.HasPrefix(k, "\x1b"):
|
||||
return Key{
|
||||
keyCode: -1,
|
||||
modifiers: modifiers,
|
||||
buttons: -1,
|
||||
r: 0,
|
||||
escape: k,
|
||||
}, true
|
||||
default:
|
||||
break modSearch
|
||||
}
|
||||
@@ -397,9 +410,15 @@ func BindKey(k, v string) {
|
||||
if v == "ToggleHelp" {
|
||||
helpBinding = k
|
||||
}
|
||||
if v == "ToggleKeyMenu" {
|
||||
kmenuBinding = k
|
||||
}
|
||||
if helpBinding == k && v != "ToggleHelp" {
|
||||
helpBinding = ""
|
||||
}
|
||||
if kmenuBinding == k && v != "ToggleKeyMenu" {
|
||||
kmenuBinding = ""
|
||||
}
|
||||
|
||||
actionNames := strings.Split(v, ",")
|
||||
if actionNames[0] == "UnbindKey" {
|
||||
@@ -458,6 +477,8 @@ func DefaultBindings() map[string]string {
|
||||
"CtrlDown": "CursorEnd",
|
||||
"CtrlShiftUp": "SelectToStart",
|
||||
"CtrlShiftDown": "SelectToEnd",
|
||||
"Alt-{": "ParagraphPrevious",
|
||||
"Alt-}": "ParagraphNext",
|
||||
"Enter": "InsertNewline",
|
||||
"CtrlH": "Backspace",
|
||||
"Backspace": "Backspace",
|
||||
@@ -490,6 +511,7 @@ func DefaultBindings() map[string]string {
|
||||
"CtrlPageUp": "PreviousTab",
|
||||
"CtrlPageDown": "NextTab",
|
||||
"CtrlG": "ToggleHelp",
|
||||
"Alt-g": "ToggleKeyMenu",
|
||||
"CtrlR": "ToggleRuler",
|
||||
"CtrlL": "JumpLine",
|
||||
"Delete": "Delete",
|
||||
@@ -509,7 +531,6 @@ func DefaultBindings() map[string]string {
|
||||
// "Alt-n": "CursorDown",
|
||||
|
||||
// Integration with file managers
|
||||
"F1": "ToggleHelp",
|
||||
"F2": "Save",
|
||||
"F3": "Find",
|
||||
"F4": "Quit",
|
||||
|
||||
@@ -349,6 +349,14 @@ func (b *Buffer) MergeCursors() {
|
||||
}
|
||||
|
||||
b.cursors = cursors
|
||||
|
||||
for i := range b.cursors {
|
||||
b.cursors[i].Num = i
|
||||
}
|
||||
|
||||
if b.curCursor >= len(b.cursors) {
|
||||
b.curCursor = len(b.cursors) - 1
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Buffer) UpdateCursors() {
|
||||
@@ -431,7 +439,7 @@ func (b *Buffer) SaveAsWithSudo(filename string) error {
|
||||
screen = nil
|
||||
|
||||
// Set up everything for the command
|
||||
cmd := exec.Command("sudo", "tee", filename)
|
||||
cmd := exec.Command(globalSettings["sucmd"].(string), "tee", filename)
|
||||
cmd.Stdin = bytes.NewBufferString(b.SaveString(b.Settings["fileformat"] == "dos"))
|
||||
|
||||
// This is a trap for Ctrl-C so that it doesn't kill micro
|
||||
|
||||
@@ -65,6 +65,10 @@ type CellView struct {
|
||||
}
|
||||
|
||||
func (c *CellView) Draw(buf *Buffer, top, height, left, width int) {
|
||||
if width <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
tabsize := int(buf.Settings["tabsize"].(float64))
|
||||
softwrap := buf.Settings["softwrap"].(bool)
|
||||
indentrunes := []rune(buf.Settings["indentchar"].(string))
|
||||
|
||||
@@ -15,7 +15,7 @@ type Colorscheme map[string]tcell.Style
|
||||
// The current colorscheme
|
||||
var colorscheme Colorscheme
|
||||
|
||||
// This takes in a syntax group and returns the colorscheme's style for that group
|
||||
// GetColor takes in a syntax group and returns the colorscheme's style for that group
|
||||
func GetColor(color string) tcell.Style {
|
||||
st := defStyle
|
||||
if color == "" {
|
||||
|
||||
@@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
@@ -14,6 +13,7 @@ import (
|
||||
"strings"
|
||||
|
||||
humanize "github.com/dustin/go-humanize"
|
||||
"github.com/zyedidia/micro/cmd/micro/shellwords"
|
||||
)
|
||||
|
||||
// A Command contains a action (a function to call) as well as information about how to autocomplete the command
|
||||
@@ -56,6 +56,7 @@ func init() {
|
||||
"Open": Open,
|
||||
"TabSwitch": TabSwitch,
|
||||
"MemUsage": MemUsage,
|
||||
"Retab": Retab,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +91,7 @@ func MakeCommand(name, function string, completions ...Completion) {
|
||||
func DefaultCommands() map[string]StrCommand {
|
||||
return map[string]StrCommand{
|
||||
"set": {"Set", []Completion{OptionCompletion, OptionValueCompletion}},
|
||||
"setlocal": {"SetLocal", []Completion{OptionCompletion, NoCompletion}},
|
||||
"setlocal": {"SetLocal", []Completion{OptionCompletion, OptionValueCompletion}},
|
||||
"show": {"Show", []Completion{OptionCompletion, NoCompletion}},
|
||||
"bind": {"Bind", []Completion{NoCompletion}},
|
||||
"run": {"Run", []Completion{NoCompletion}},
|
||||
@@ -111,6 +112,7 @@ func DefaultCommands() map[string]StrCommand {
|
||||
"open": {"Open", []Completion{FileCompletion}},
|
||||
"tabswitch": {"TabSwitch", []Completion{NoCompletion}},
|
||||
"memusage": {"MemUsage", []Completion{NoCompletion}},
|
||||
"retab": {"Retab", []Completion{NoCompletion}},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +199,10 @@ func PluginCmd(args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
func Retab(args []string) {
|
||||
CurView().Retab(true)
|
||||
}
|
||||
|
||||
// TabSwitch switches to a given tab either by name or by number
|
||||
func TabSwitch(args []string) {
|
||||
if len(args) > 0 {
|
||||
@@ -230,10 +236,18 @@ func TabSwitch(args []string) {
|
||||
func Cd(args []string) {
|
||||
if len(args) > 0 {
|
||||
path := ReplaceHome(args[0])
|
||||
os.Chdir(path)
|
||||
err := os.Chdir(path)
|
||||
if err != nil {
|
||||
messenger.Error("Error with cd: ", err)
|
||||
return
|
||||
}
|
||||
wd, _ := os.Getwd()
|
||||
for _, tab := range tabs {
|
||||
for _, view := range tab.views {
|
||||
wd, _ := os.Getwd()
|
||||
if len(view.Buf.name) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
view.Buf.Path, _ = MakeRelative(view.Buf.AbsPath, wd)
|
||||
if p, _ := filepath.Abs(view.Buf.Path); !strings.Contains(p, wd) {
|
||||
view.Buf.Path = view.Buf.AbsPath
|
||||
@@ -272,7 +286,12 @@ func Open(args []string) {
|
||||
if len(args) > 0 {
|
||||
filename := args[0]
|
||||
// the filename might or might not be quoted, so unquote first then join the strings.
|
||||
filename = strings.Join(SplitCommandArgs(filename), " ")
|
||||
args, err := shellwords.Split(filename)
|
||||
if err != nil {
|
||||
messenger.Error("Error parsing args ", err)
|
||||
return
|
||||
}
|
||||
filename = strings.Join(args, " ")
|
||||
|
||||
CurView().Open(filename)
|
||||
} else {
|
||||
@@ -482,7 +501,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(JoinCommandArgs(args...), false, true)
|
||||
HandleShellCommand(shellwords.Join(args...), false, true)
|
||||
}
|
||||
|
||||
// Quit closes the main view
|
||||
@@ -503,24 +522,35 @@ func Save(args []string) {
|
||||
|
||||
// Replace runs search and replace
|
||||
func Replace(args []string) {
|
||||
if len(args) < 2 || len(args) > 3 {
|
||||
if len(args) < 2 || len(args) > 4 {
|
||||
// We need to find both a search and replace expression
|
||||
messenger.Error("Invalid replace statement: " + strings.Join(args, " "))
|
||||
return
|
||||
}
|
||||
|
||||
allAtOnce := false
|
||||
if len(args) == 3 {
|
||||
// user added -a flag
|
||||
if args[2] == "-a" {
|
||||
allAtOnce = true
|
||||
} else {
|
||||
messenger.Error("Invalid replace flag: " + args[2])
|
||||
return
|
||||
all := false
|
||||
noRegex := false
|
||||
|
||||
if len(args) > 2 {
|
||||
for _, arg := range args[2:] {
|
||||
switch arg {
|
||||
case "-a":
|
||||
all = true
|
||||
case "-l":
|
||||
noRegex = true
|
||||
default:
|
||||
messenger.Error("Invalid flag: " + arg)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
search := string(args[0])
|
||||
|
||||
if noRegex {
|
||||
search = regexp.QuoteMeta(search)
|
||||
}
|
||||
|
||||
replace := string(args[1])
|
||||
|
||||
regex, err := regexp.Compile("(?m)" + search)
|
||||
@@ -556,7 +586,7 @@ func Replace(args []string) {
|
||||
view.Buf.MultipleReplace(deltas)
|
||||
}
|
||||
|
||||
if allAtOnce {
|
||||
if all {
|
||||
replaceAll()
|
||||
} else {
|
||||
for {
|
||||
@@ -616,15 +646,18 @@ func ReplaceAll(args []string) {
|
||||
|
||||
// RunShellCommand executes a shell command and returns the output/error
|
||||
func RunShellCommand(input string) (string, error) {
|
||||
inputCmd := SplitCommandArgs(input)[0]
|
||||
args := SplitCommandArgs(input)[1:]
|
||||
args, err := shellwords.Split(input)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
inputCmd := args[0]
|
||||
|
||||
cmd := exec.Command(inputCmd, args...)
|
||||
cmd := exec.Command(inputCmd, args[1:]...)
|
||||
outputBytes := &bytes.Buffer{}
|
||||
cmd.Stdout = outputBytes
|
||||
cmd.Stderr = outputBytes
|
||||
cmd.Start()
|
||||
err := cmd.Wait() // wait for command to finish
|
||||
err = cmd.Wait() // wait for command to finish
|
||||
outstring := outputBytes.String()
|
||||
return outstring, err
|
||||
}
|
||||
@@ -633,7 +666,11 @@ func RunShellCommand(input string) (string, error) {
|
||||
// The openTerm argument specifies whether a terminal should be opened (for viewing output
|
||||
// or interacting with stdin)
|
||||
func HandleShellCommand(input string, openTerm bool, waitToFinish bool) string {
|
||||
inputCmd := SplitCommandArgs(input)[0]
|
||||
args, err := shellwords.Split(input)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
inputCmd := args[0]
|
||||
if !openTerm {
|
||||
// Simply run the command in the background and notify the user when it's done
|
||||
messenger.Message("Running...")
|
||||
@@ -658,13 +695,13 @@ func HandleShellCommand(input string, openTerm bool, waitToFinish bool) string {
|
||||
screen.Fini()
|
||||
screen = nil
|
||||
|
||||
args := SplitCommandArgs(input)[1:]
|
||||
args := args[1:]
|
||||
|
||||
// Set up everything for the command
|
||||
var outputBuf bytes.Buffer
|
||||
var output string
|
||||
cmd := exec.Command(inputCmd, args...)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = io.MultiWriter(os.Stdout, &outputBuf)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
// This is a trap for Ctrl-C so that it doesn't kill micro
|
||||
@@ -680,7 +717,6 @@ func HandleShellCommand(input string, openTerm bool, waitToFinish bool) string {
|
||||
cmd.Start()
|
||||
err := cmd.Wait()
|
||||
|
||||
output := outputBuf.String()
|
||||
if err != nil {
|
||||
output = err.Error()
|
||||
}
|
||||
@@ -700,7 +736,12 @@ func HandleShellCommand(input string, openTerm bool, waitToFinish bool) string {
|
||||
|
||||
// HandleCommand handles input from the user
|
||||
func HandleCommand(input string) {
|
||||
args := SplitCommandArgs(input)
|
||||
args, err := shellwords.Split(input)
|
||||
if err != nil {
|
||||
messenger.Error("Error parsing args ", err)
|
||||
return
|
||||
}
|
||||
|
||||
inputCmd := args[0]
|
||||
|
||||
if _, ok := commands[inputCmd]; !ok {
|
||||
|
||||
@@ -28,13 +28,15 @@ type Cursor struct {
|
||||
Num int
|
||||
}
|
||||
|
||||
// Goto puts the cursor at the given cursor's location and gives the current cursor its selection too
|
||||
// Goto puts the cursor at the given cursor's location and gives
|
||||
// the current cursor its selection too
|
||||
func (c *Cursor) Goto(b Cursor) {
|
||||
c.X, c.Y, c.LastVisualX = b.X, b.Y, b.LastVisualX
|
||||
c.OrigSelection, c.CurSelection = b.OrigSelection, b.CurSelection
|
||||
}
|
||||
|
||||
// CopySelection copies the user's selection to either "primary" or "clipboard"
|
||||
// CopySelection copies the user's selection to either "primary"
|
||||
// or "clipboard"
|
||||
func (c *Cursor) CopySelection(target string) {
|
||||
if c.HasSelection() {
|
||||
if target != "primary" || c.buf.Settings["useprimary"].(bool) {
|
||||
@@ -151,7 +153,8 @@ func (c *Cursor) SelectWord() {
|
||||
c.Loc = c.CurSelection[1]
|
||||
}
|
||||
|
||||
// AddWordToSelection adds the word the cursor is currently on to the selection
|
||||
// AddWordToSelection adds the word the cursor is currently on
|
||||
// to the selection
|
||||
func (c *Cursor) AddWordToSelection() {
|
||||
if c.Loc.GreaterThan(c.OrigSelection[0]) && c.Loc.LessThan(c.OrigSelection[1]) {
|
||||
c.CurSelection = c.OrigSelection
|
||||
@@ -183,7 +186,8 @@ func (c *Cursor) AddWordToSelection() {
|
||||
c.Loc = c.CurSelection[1]
|
||||
}
|
||||
|
||||
// SelectTo selects from the current cursor location to the given location
|
||||
// SelectTo selects from the current cursor location to the given
|
||||
// location
|
||||
func (c *Cursor) SelectTo(loc Loc) {
|
||||
if loc.GreaterThan(c.OrigSelection[0]) {
|
||||
c.SetSelectionStart(c.OrigSelection[0])
|
||||
@@ -280,7 +284,8 @@ func (c *Cursor) Down() {
|
||||
c.DownN(1)
|
||||
}
|
||||
|
||||
// Left moves the cursor left one cell (if possible) or to the last line if it is at the beginning
|
||||
// Left moves the cursor left one cell (if possible) or to
|
||||
// the previous line if it is at the beginning
|
||||
func (c *Cursor) Left() {
|
||||
if c.Loc == c.buf.Start() {
|
||||
return
|
||||
@@ -294,7 +299,8 @@ func (c *Cursor) Left() {
|
||||
c.LastVisualX = c.GetVisualX()
|
||||
}
|
||||
|
||||
// Right moves the cursor right one cell (if possible) or to the next line if it is at the end
|
||||
// Right moves the cursor right one cell (if possible) or
|
||||
// to the next line if it is at the end
|
||||
func (c *Cursor) Right() {
|
||||
if c.Loc == c.buf.End() {
|
||||
return
|
||||
@@ -320,7 +326,9 @@ func (c *Cursor) Start() {
|
||||
c.LastVisualX = c.GetVisualX()
|
||||
}
|
||||
|
||||
// GetCharPosInLine gets the char position of a visual x y coordinate (this is necessary because tabs are 1 char but 4 visual spaces)
|
||||
// GetCharPosInLine gets the char position of a visual x y
|
||||
// coordinate (this is necessary because tabs are 1 char but
|
||||
// 4 visual spaces)
|
||||
func (c *Cursor) GetCharPosInLine(lineNum, visualPos int) int {
|
||||
// Get the tab size
|
||||
tabSize := int(c.buf.Settings["tabsize"].(float64))
|
||||
@@ -355,8 +363,9 @@ func (c *Cursor) StoreVisualX() {
|
||||
c.LastVisualX = c.GetVisualX()
|
||||
}
|
||||
|
||||
// Relocate makes sure that the cursor is inside the bounds of the buffer
|
||||
// If it isn't, it moves it to be within the buffer's lines
|
||||
// Relocate makes sure that the cursor is inside the bounds
|
||||
// of the buffer If it isn't, it moves it to be within the
|
||||
// buffer's lines
|
||||
func (c *Cursor) Relocate() {
|
||||
if c.Y < 0 {
|
||||
c.Y = 0
|
||||
|
||||
@@ -2,7 +2,7 @@ package highlight
|
||||
|
||||
import "regexp"
|
||||
|
||||
// DetectFiletype will use the list of syntax definitions provided and the filename and first line of the file
|
||||
// MatchFiletype will use the list of syntax definitions provided and the filename and first line of the file
|
||||
// to determine the filetype of the file
|
||||
// It will return the corresponding syntax definition for the filetype
|
||||
func MatchFiletype(ftdetect [2]*regexp.Regexp, filename string, firstLine []byte) bool {
|
||||
|
||||
20
cmd/micro/keymenu.go
Normal file
20
cmd/micro/keymenu.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
// DisplayKeyMenu displays the nano-style key menu at the bottom of the screen
|
||||
func DisplayKeyMenu() {
|
||||
w, h := screen.Size()
|
||||
|
||||
bot := h - 3
|
||||
|
||||
display := []string{"^Q Quit, ^S Save, ^O Open, ^G Help, ^E Command Bar, ^K Cut Line", "^F Find, ^Z Undo, ^Y Redo, ^A Select All, ^D Duplicate Line, ^T New Tab"}
|
||||
|
||||
for y := 0; y < len(display); y++ {
|
||||
for x := 0; x < w; x++ {
|
||||
if x < len(display[y]) {
|
||||
screen.SetContent(x, bot+y, rune(display[y][x]), nil, defStyle)
|
||||
} else {
|
||||
screen.SetContent(x, bot+y, ' ', nil, defStyle)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ type Loc struct {
|
||||
X, Y int
|
||||
}
|
||||
|
||||
// Diff returns the distance between two locations
|
||||
func Diff(a, b Loc, buf *Buffer) int {
|
||||
if a.Y == b.Y {
|
||||
if a.X > b.X {
|
||||
|
||||
@@ -28,6 +28,7 @@ func init() {
|
||||
L.SetGlobal("import", luar.New(L, Import))
|
||||
}
|
||||
|
||||
// LoadFile loads a lua file
|
||||
func LoadFile(module string, file string, data string) error {
|
||||
pluginDef := "local P = {};" + module + " = P;setmetatable(" + module + ", {__index = _G});setfenv(1, P);"
|
||||
|
||||
@@ -39,40 +40,43 @@ func LoadFile(module string, file string, data string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Import allows a lua plugin to import a package
|
||||
func Import(pkg string) *lua.LTable {
|
||||
switch pkg {
|
||||
case "fmt":
|
||||
return ImportFmt()
|
||||
return importFmt()
|
||||
case "io":
|
||||
return ImportIo()
|
||||
case "ioutil":
|
||||
return ImportIoUtil()
|
||||
return importIo()
|
||||
case "io/ioutil", "ioutil":
|
||||
return importIoUtil()
|
||||
case "net":
|
||||
return ImportNet()
|
||||
return importNet()
|
||||
case "math":
|
||||
return ImportMath()
|
||||
return importMath()
|
||||
case "math/rand":
|
||||
return importMathRand()
|
||||
case "os":
|
||||
return ImportOs()
|
||||
return importOs()
|
||||
case "runtime":
|
||||
return ImportRuntime()
|
||||
return importRuntime()
|
||||
case "path":
|
||||
return ImportPath()
|
||||
return importPath()
|
||||
case "filepath":
|
||||
return ImportFilePath()
|
||||
return importFilePath()
|
||||
case "strings":
|
||||
return ImportStrings()
|
||||
return importStrings()
|
||||
case "regexp":
|
||||
return ImportRegexp()
|
||||
return importRegexp()
|
||||
case "errors":
|
||||
return ImportErrors()
|
||||
return importErrors()
|
||||
case "time":
|
||||
return ImportTime()
|
||||
return importTime()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func ImportFmt() *lua.LTable {
|
||||
func importFmt() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "tErrorf", luar.New(L, fmt.Errorf))
|
||||
@@ -98,7 +102,7 @@ func ImportFmt() *lua.LTable {
|
||||
return pkg
|
||||
}
|
||||
|
||||
func ImportIo() *lua.LTable {
|
||||
func importIo() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "Copy", luar.New(L, io.Copy))
|
||||
@@ -122,7 +126,7 @@ func ImportIo() *lua.LTable {
|
||||
return pkg
|
||||
}
|
||||
|
||||
func ImportIoUtil() *lua.LTable {
|
||||
func importIoUtil() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "ReadAll", luar.New(L, ioutil.ReadAll))
|
||||
@@ -133,7 +137,7 @@ func ImportIoUtil() *lua.LTable {
|
||||
return pkg
|
||||
}
|
||||
|
||||
func ImportNet() *lua.LTable {
|
||||
func importNet() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "CIDRMask", luar.New(L, net.CIDRMask))
|
||||
@@ -201,7 +205,7 @@ func ImportNet() *lua.LTable {
|
||||
return pkg
|
||||
}
|
||||
|
||||
func ImportMath() *lua.LTable {
|
||||
func importMath() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "Abs", luar.New(L, math.Abs))
|
||||
@@ -269,7 +273,7 @@ func ImportMath() *lua.LTable {
|
||||
return pkg
|
||||
}
|
||||
|
||||
func ImportMathRand() *lua.LTable {
|
||||
func importMathRand() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "ExpFloat64", luar.New(L, rand.ExpFloat64))
|
||||
@@ -289,7 +293,7 @@ func ImportMathRand() *lua.LTable {
|
||||
return pkg
|
||||
}
|
||||
|
||||
func ImportOs() *lua.LTable {
|
||||
func importOs() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "Args", luar.New(L, os.Args))
|
||||
@@ -380,7 +384,7 @@ func ImportOs() *lua.LTable {
|
||||
return pkg
|
||||
}
|
||||
|
||||
func ImportRuntime() *lua.LTable {
|
||||
func importRuntime() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "GC", luar.New(L, runtime.GC))
|
||||
@@ -392,7 +396,7 @@ func ImportRuntime() *lua.LTable {
|
||||
return pkg
|
||||
}
|
||||
|
||||
func ImportPath() *lua.LTable {
|
||||
func importPath() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "Base", luar.New(L, path.Base))
|
||||
@@ -408,7 +412,7 @@ func ImportPath() *lua.LTable {
|
||||
return pkg
|
||||
}
|
||||
|
||||
func ImportFilePath() *lua.LTable {
|
||||
func importFilePath() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "Join", luar.New(L, filepath.Join))
|
||||
@@ -434,7 +438,7 @@ func ImportFilePath() *lua.LTable {
|
||||
return pkg
|
||||
}
|
||||
|
||||
func ImportStrings() *lua.LTable {
|
||||
func importStrings() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "Contains", luar.New(L, strings.Contains))
|
||||
@@ -484,7 +488,7 @@ func ImportStrings() *lua.LTable {
|
||||
return pkg
|
||||
}
|
||||
|
||||
func ImportRegexp() *lua.LTable {
|
||||
func importRegexp() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "Match", luar.New(L, regexp.Match))
|
||||
@@ -499,7 +503,7 @@ func ImportRegexp() *lua.LTable {
|
||||
return pkg
|
||||
}
|
||||
|
||||
func ImportErrors() *lua.LTable {
|
||||
func importErrors() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "New", luar.New(L, errors.New))
|
||||
@@ -507,7 +511,7 @@ func ImportErrors() *lua.LTable {
|
||||
return pkg
|
||||
}
|
||||
|
||||
func ImportTime() *lua.LTable {
|
||||
func importTime() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "After", luar.New(L, time.After))
|
||||
|
||||
@@ -3,12 +3,14 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/mattn/go-runewidth"
|
||||
"github.com/zyedidia/clipboard"
|
||||
"github.com/zyedidia/micro/cmd/micro/shellwords"
|
||||
"github.com/zyedidia/tcell"
|
||||
)
|
||||
|
||||
@@ -271,9 +273,16 @@ func (m *Messenger) Prompt(prompt, placeholder, historyType string, completionTy
|
||||
response, canceled = m.response, false
|
||||
m.history[historyType][len(m.history[historyType])-1] = response
|
||||
case tcell.KeyTab:
|
||||
args := SplitCommandArgs(m.response)
|
||||
currentArgNum := len(args) - 1
|
||||
currentArg := args[currentArgNum]
|
||||
args, err := shellwords.Split(m.response)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
currentArg := ""
|
||||
currentArgNum := 0
|
||||
if len(args) > 0 {
|
||||
currentArgNum = len(args) - 1
|
||||
currentArg = args[currentArgNum]
|
||||
}
|
||||
var completionType Completion
|
||||
|
||||
if completionTypes[0] == CommandCompletion && currentArgNum > 0 {
|
||||
@@ -314,7 +323,7 @@ func (m *Messenger) Prompt(prompt, placeholder, historyType string, completionTy
|
||||
}
|
||||
|
||||
if chosen != "" {
|
||||
m.response = JoinCommandArgs(append(args[:len(args)-1], chosen)...)
|
||||
m.response = shellwords.Join(append(args[:len(args)-1], chosen)...)
|
||||
m.cursorx = Count(m.response)
|
||||
}
|
||||
}
|
||||
@@ -339,62 +348,139 @@ func (m *Messenger) Prompt(prompt, placeholder, historyType string, completionTy
|
||||
return response, canceled
|
||||
}
|
||||
|
||||
func (m *Messenger) UpHistory(history []string) {
|
||||
if m.historyNum > 0 {
|
||||
m.historyNum--
|
||||
m.response = history[m.historyNum]
|
||||
m.cursorx = Count(m.response)
|
||||
}
|
||||
}
|
||||
func (m *Messenger) DownHistory(history []string) {
|
||||
if m.historyNum < len(history)-1 {
|
||||
m.historyNum++
|
||||
m.response = history[m.historyNum]
|
||||
m.cursorx = Count(m.response)
|
||||
}
|
||||
}
|
||||
func (m *Messenger) CursorLeft() {
|
||||
if m.cursorx > 0 {
|
||||
m.cursorx--
|
||||
}
|
||||
}
|
||||
func (m *Messenger) CursorRight() {
|
||||
if m.cursorx < Count(m.response) {
|
||||
m.cursorx++
|
||||
}
|
||||
}
|
||||
func (m *Messenger) Start() {
|
||||
m.cursorx = 0
|
||||
}
|
||||
func (m *Messenger) End() {
|
||||
m.cursorx = Count(m.response)
|
||||
}
|
||||
func (m *Messenger) Backspace() {
|
||||
if m.cursorx > 0 {
|
||||
m.response = string([]rune(m.response)[:m.cursorx-1]) + string([]rune(m.response)[m.cursorx:])
|
||||
m.cursorx--
|
||||
}
|
||||
}
|
||||
func (m *Messenger) Paste() {
|
||||
clip, _ := clipboard.ReadAll("clipboard")
|
||||
m.response = Insert(m.response, m.cursorx, clip)
|
||||
m.cursorx += Count(clip)
|
||||
}
|
||||
func (m *Messenger) WordLeft() {
|
||||
response := []rune(m.response)
|
||||
m.CursorLeft()
|
||||
if m.cursorx <= 0 {
|
||||
return
|
||||
}
|
||||
for IsWhitespace(response[m.cursorx]) {
|
||||
if m.cursorx <= 0 {
|
||||
return
|
||||
}
|
||||
m.CursorLeft()
|
||||
}
|
||||
m.CursorLeft()
|
||||
for IsWordChar(string(response[m.cursorx])) {
|
||||
if m.cursorx <= 0 {
|
||||
return
|
||||
}
|
||||
m.CursorLeft()
|
||||
}
|
||||
m.CursorRight()
|
||||
}
|
||||
func (m *Messenger) WordRight() {
|
||||
response := []rune(m.response)
|
||||
if m.cursorx >= len(response) {
|
||||
return
|
||||
}
|
||||
for IsWhitespace(response[m.cursorx]) {
|
||||
m.CursorRight()
|
||||
if m.cursorx >= len(response) {
|
||||
m.CursorRight()
|
||||
return
|
||||
}
|
||||
}
|
||||
m.CursorRight()
|
||||
if m.cursorx >= len(response) {
|
||||
return
|
||||
}
|
||||
for IsWordChar(string(response[m.cursorx])) {
|
||||
m.CursorRight()
|
||||
if m.cursorx >= len(response) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
func (m *Messenger) DeleteWordLeft() {
|
||||
m.WordLeft()
|
||||
m.response = string([]rune(m.response)[:m.cursorx])
|
||||
}
|
||||
|
||||
// HandleEvent handles an event for the prompter
|
||||
func (m *Messenger) HandleEvent(event tcell.Event, history []string) {
|
||||
switch e := event.(type) {
|
||||
case *tcell.EventKey:
|
||||
if e.Key() != tcell.KeyRune || e.Modifiers() != 0 {
|
||||
for key, actions := range bindings {
|
||||
if e.Key() == key.keyCode {
|
||||
if e.Key() == tcell.KeyRune {
|
||||
if e.Rune() != key.r {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if e.Modifiers() == key.modifiers {
|
||||
for _, action := range actions {
|
||||
funcName := FuncName(action)
|
||||
switch funcName {
|
||||
case "main.(*View).CursorUp":
|
||||
if m.historyNum > 0 {
|
||||
m.historyNum--
|
||||
m.response = history[m.historyNum]
|
||||
m.cursorx = Count(m.response)
|
||||
}
|
||||
case "main.(*View).CursorDown":
|
||||
if m.historyNum < len(history)-1 {
|
||||
m.historyNum++
|
||||
m.response = history[m.historyNum]
|
||||
m.cursorx = Count(m.response)
|
||||
}
|
||||
case "main.(*View).CursorLeft":
|
||||
if m.cursorx > 0 {
|
||||
m.cursorx--
|
||||
}
|
||||
case "main.(*View).CursorRight":
|
||||
if m.cursorx < Count(m.response) {
|
||||
m.cursorx++
|
||||
}
|
||||
case "main.(*View).CursorStart", "main.(*View).StartOfLine":
|
||||
m.cursorx = 0
|
||||
case "main.(*View).CursorEnd", "main.(*View).EndOfLine":
|
||||
m.cursorx = Count(m.response)
|
||||
case "main.(*View).Backspace":
|
||||
if m.cursorx > 0 {
|
||||
m.response = string([]rune(m.response)[:m.cursorx-1]) + string([]rune(m.response)[m.cursorx:])
|
||||
m.cursorx--
|
||||
}
|
||||
case "main.(*View).Paste":
|
||||
clip, _ := clipboard.ReadAll("clipboard")
|
||||
m.response = Insert(m.response, m.cursorx, clip)
|
||||
m.cursorx += Count(clip)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch e.Key() {
|
||||
case tcell.KeyCtrlA:
|
||||
m.Start()
|
||||
case tcell.KeyCtrlE:
|
||||
m.End()
|
||||
case tcell.KeyUp:
|
||||
m.UpHistory(history)
|
||||
case tcell.KeyDown:
|
||||
m.DownHistory(history)
|
||||
case tcell.KeyLeft:
|
||||
if e.Modifiers() == tcell.ModCtrl {
|
||||
m.Start()
|
||||
} else if e.Modifiers() == tcell.ModAlt || e.Modifiers() == tcell.ModMeta {
|
||||
m.WordLeft()
|
||||
} else {
|
||||
m.CursorLeft()
|
||||
}
|
||||
case tcell.KeyRight:
|
||||
if e.Modifiers() == tcell.ModCtrl {
|
||||
m.End()
|
||||
} else if e.Modifiers() == tcell.ModAlt || e.Modifiers() == tcell.ModMeta {
|
||||
m.WordRight()
|
||||
} else {
|
||||
m.CursorRight()
|
||||
}
|
||||
case tcell.KeyBackspace2, tcell.KeyBackspace:
|
||||
if e.Modifiers() == tcell.ModCtrl || e.Modifiers() == tcell.ModAlt || e.Modifiers() == tcell.ModMeta {
|
||||
m.DeleteWordLeft()
|
||||
} else {
|
||||
m.Backspace()
|
||||
}
|
||||
case tcell.KeyCtrlW:
|
||||
m.DeleteWordLeft()
|
||||
case tcell.KeyCtrlV:
|
||||
m.Paste()
|
||||
case tcell.KeyCtrlF:
|
||||
m.WordRight()
|
||||
case tcell.KeyCtrlB:
|
||||
m.WordLeft()
|
||||
case tcell.KeyRune:
|
||||
m.response = Insert(m.response, m.cursorx, string(e.Rune()))
|
||||
m.cursorx++
|
||||
@@ -485,6 +571,59 @@ func (m *Messenger) Display() {
|
||||
}
|
||||
}
|
||||
|
||||
// LoadHistory attempts to load user history from configDir/buffers/history
|
||||
// into the history map
|
||||
// The savehistory option must be on
|
||||
func (m *Messenger) LoadHistory() {
|
||||
if GetGlobalOption("savehistory").(bool) {
|
||||
file, err := os.Open(configDir + "/buffers/history")
|
||||
var decodedMap map[string][]string
|
||||
if err == nil {
|
||||
decoder := gob.NewDecoder(file)
|
||||
err = decoder.Decode(&decodedMap)
|
||||
file.Close()
|
||||
|
||||
if err != nil {
|
||||
m.Error("Error loading history:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if decodedMap != nil {
|
||||
m.history = decodedMap
|
||||
} else {
|
||||
m.history = make(map[string][]string)
|
||||
}
|
||||
} else {
|
||||
m.history = make(map[string][]string)
|
||||
}
|
||||
}
|
||||
|
||||
// SaveHistory saves the user's command history to configDir/buffers/history
|
||||
// only if the savehistory option is on
|
||||
func (m *Messenger) SaveHistory() {
|
||||
if GetGlobalOption("savehistory").(bool) {
|
||||
// Don't save history past 100
|
||||
for k, v := range m.history {
|
||||
if len(v) > 100 {
|
||||
m.history[k] = v[0:100]
|
||||
}
|
||||
}
|
||||
|
||||
file, err := os.Create(configDir + "/buffers/history")
|
||||
if err == nil {
|
||||
encoder := gob.NewEncoder(file)
|
||||
|
||||
err = encoder.Encode(m.history)
|
||||
if err != nil {
|
||||
m.Error("Error saving history:", err)
|
||||
return
|
||||
}
|
||||
file.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A GutterMessage is a message displayed on the side of the editor
|
||||
type GutterMessage struct {
|
||||
lineNum int
|
||||
|
||||
@@ -225,6 +225,9 @@ func RedrawAll() {
|
||||
}
|
||||
DisplayTabs()
|
||||
messenger.Display()
|
||||
if globalSettings["keymenu"].(bool) {
|
||||
DisplayKeyMenu()
|
||||
}
|
||||
screen.Show()
|
||||
}
|
||||
|
||||
@@ -339,7 +342,7 @@ func main() {
|
||||
// Create a new messenger
|
||||
// This is used for sending the user messages in the bottom of the editor
|
||||
messenger = new(Messenger)
|
||||
messenger.history = make(map[string][]string)
|
||||
messenger.LoadHistory()
|
||||
|
||||
// Now we load the input
|
||||
buffers := LoadInput()
|
||||
@@ -473,6 +476,8 @@ func main() {
|
||||
}
|
||||
|
||||
for event != nil {
|
||||
didAction := false
|
||||
|
||||
switch e := event.(type) {
|
||||
case *tcell.EventResize:
|
||||
for _, t := range tabs {
|
||||
@@ -502,24 +507,36 @@ func main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if e.Buttons() == tcell.WheelUp || e.Buttons() == tcell.WheelDown {
|
||||
var view *View
|
||||
x, y := e.Position()
|
||||
for _, v := range tabs[curTab].views {
|
||||
if x >= v.x && x < v.x+v.Width && y >= v.y && y < v.y+v.Height {
|
||||
view = tabs[curTab].views[v.Num]
|
||||
}
|
||||
}
|
||||
view.HandleEvent(e)
|
||||
didAction = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function checks the mouse event for the possibility of changing the current tab
|
||||
// If the tab was changed it returns true
|
||||
if TabbarHandleMouseEvent(event) {
|
||||
break
|
||||
}
|
||||
if !didAction {
|
||||
// This function checks the mouse event for the possibility of changing the current tab
|
||||
// If the tab was changed it returns true
|
||||
if TabbarHandleMouseEvent(event) {
|
||||
break
|
||||
}
|
||||
|
||||
if searching {
|
||||
// Since searching is done in real time, we need to redraw every time
|
||||
// there is a new event in the search bar so we need a special function
|
||||
// to run instead of the standard HandleEvent.
|
||||
HandleSearchEvent(event, CurView())
|
||||
} else {
|
||||
// Send it to the view
|
||||
CurView().HandleEvent(event)
|
||||
if searching {
|
||||
// Since searching is done in real time, we need to redraw every time
|
||||
// there is a new event in the search bar so we need a special function
|
||||
// to run instead of the standard HandleEvent.
|
||||
HandleSearchEvent(event, CurView())
|
||||
} else {
|
||||
// Send it to the view
|
||||
CurView().HandleEvent(event)
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
|
||||
@@ -146,7 +146,7 @@ func LoadPlugins() {
|
||||
|
||||
pluginLuaName := luaPluginName(pluginName)
|
||||
|
||||
if err := LoadFile(pluginName, pluginName, string(data)); err != nil {
|
||||
if err := LoadFile(pluginLuaName, pluginLuaName, string(data)); err != nil {
|
||||
TermMessage(err)
|
||||
continue
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
18
cmd/micro/scrollbar.go
Normal file
18
cmd/micro/scrollbar.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
type ScrollBar struct {
|
||||
view *View
|
||||
}
|
||||
|
||||
func (sb *ScrollBar) Display() {
|
||||
style := defStyle.Reverse(true)
|
||||
screen.SetContent(sb.view.x+sb.view.Width-1, sb.view.y+sb.Pos(), ' ', nil, style)
|
||||
}
|
||||
|
||||
func (sb *ScrollBar) Pos() int {
|
||||
numlines := sb.view.Buf.NumLines
|
||||
h := sb.view.Height
|
||||
filepercent := float32(sb.view.Topline) / float32(numlines)
|
||||
|
||||
return int(filepercent * float32(h))
|
||||
}
|
||||
@@ -64,7 +64,12 @@ func HandleSearchEvent(event tcell.Event, v *View) {
|
||||
// Exit the search mode
|
||||
ExitSearch(v)
|
||||
return
|
||||
case tcell.KeyCtrlQ, tcell.KeyCtrlC, tcell.KeyEnter:
|
||||
case tcell.KeyEnter:
|
||||
// If the user has pressed Enter, they want this to be the lastSearch
|
||||
lastSearch = messenger.response
|
||||
EndSearch()
|
||||
return
|
||||
case tcell.KeyCtrlQ, tcell.KeyCtrlC:
|
||||
// Done
|
||||
EndSearch()
|
||||
return
|
||||
@@ -179,9 +184,7 @@ func Search(searchStr string, v *View, down bool) {
|
||||
found = searchUp(r, v, v.Buf.End(), searchStart)
|
||||
}
|
||||
}
|
||||
if found {
|
||||
lastSearch = searchStr
|
||||
} else {
|
||||
if !found {
|
||||
v.Cursor.ResetSelection()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +193,6 @@ func GetOption(name string) interface{} {
|
||||
func DefaultGlobalSettings() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"autoindent": true,
|
||||
"keepautoindent": false,
|
||||
"autosave": false,
|
||||
"colorcolumn": float64(0),
|
||||
"colorscheme": "default",
|
||||
@@ -204,27 +203,30 @@ func DefaultGlobalSettings() map[string]interface{} {
|
||||
"ignorecase": false,
|
||||
"indentchar": " ",
|
||||
"infobar": true,
|
||||
"keepautoindent": false,
|
||||
"keymenu": false,
|
||||
"mouse": true,
|
||||
"pluginchannels": []string{"https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json"},
|
||||
"pluginrepos": []string{},
|
||||
"rmtrailingws": false,
|
||||
"ruler": true,
|
||||
"savecursor": false,
|
||||
"savehistory": true,
|
||||
"saveundo": false,
|
||||
"scrollspeed": float64(2),
|
||||
"scrollbar": false,
|
||||
"scrollmargin": float64(3),
|
||||
"scrollspeed": float64(2),
|
||||
"softwrap": false,
|
||||
"splitRight": true,
|
||||
"splitBottom": true,
|
||||
"splitbottom": true,
|
||||
"splitright": true,
|
||||
"statusline": true,
|
||||
"sucmd": "sudo",
|
||||
"syntax": true,
|
||||
"tabmovement": false,
|
||||
"tabsize": float64(4),
|
||||
"tabstospaces": false,
|
||||
"termtitle": false,
|
||||
"pluginchannels": []string{
|
||||
"https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json",
|
||||
},
|
||||
"pluginrepos": []string{},
|
||||
"useprimary": true,
|
||||
"useprimary": true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +235,6 @@ func DefaultGlobalSettings() map[string]interface{} {
|
||||
func DefaultLocalSettings() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"autoindent": true,
|
||||
"keepautoindent": false,
|
||||
"autosave": false,
|
||||
"colorcolumn": float64(0),
|
||||
"cursorline": true,
|
||||
@@ -243,15 +244,17 @@ func DefaultLocalSettings() map[string]interface{} {
|
||||
"filetype": "Unknown",
|
||||
"ignorecase": false,
|
||||
"indentchar": " ",
|
||||
"keepautoindent": false,
|
||||
"rmtrailingws": false,
|
||||
"ruler": true,
|
||||
"savecursor": false,
|
||||
"saveundo": false,
|
||||
"scrollspeed": float64(2),
|
||||
"scrollbar": false,
|
||||
"scrollmargin": float64(3),
|
||||
"scrollspeed": float64(2),
|
||||
"softwrap": false,
|
||||
"splitRight": true,
|
||||
"splitBottom": true,
|
||||
"splitbottom": true,
|
||||
"splitright": true,
|
||||
"statusline": true,
|
||||
"syntax": true,
|
||||
"tabmovement": false,
|
||||
@@ -311,7 +314,7 @@ func SetOption(option, value string) error {
|
||||
}
|
||||
}
|
||||
|
||||
if option == "infobar" {
|
||||
if option == "infobar" || option == "keymenu" {
|
||||
for _, tab := range tabs {
|
||||
tab.Resize()
|
||||
}
|
||||
@@ -325,10 +328,12 @@ func SetOption(option, value string) error {
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := CurView().Buf.Settings[option]; ok {
|
||||
for _, tab := range tabs {
|
||||
for _, view := range tab.views {
|
||||
SetLocalOption(option, value, view)
|
||||
if len(tabs) != 0 {
|
||||
if _, ok := CurView().Buf.Settings[option]; ok {
|
||||
for _, tab := range tabs {
|
||||
for _, view := range tab.views {
|
||||
SetLocalOption(option, value, view)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
cmd/micro/shellwords/LICENSE
Normal file
21
cmd/micro/shellwords/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Yasuhiro Matsumoto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
49
cmd/micro/shellwords/README.md
Normal file
49
cmd/micro/shellwords/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
This is a modified version of `go-shellwords` for the micro editor.
|
||||
|
||||
# go-shellwords
|
||||
|
||||
[](https://coveralls.io/r/mattn/go-shellwords?branch=master)
|
||||
[](https://travis-ci.org/mattn/go-shellwords)
|
||||
|
||||
Parse line as shell words.
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
args, err := shellwords.Parse("./foo --bar=baz")
|
||||
// args should be ["./foo", "--bar=baz"]
|
||||
```
|
||||
|
||||
```go
|
||||
os.Setenv("FOO", "bar")
|
||||
p := shellwords.NewParser()
|
||||
p.ParseEnv = true
|
||||
args, err := p.Parse("./foo $FOO")
|
||||
// args should be ["./foo", "bar"]
|
||||
```
|
||||
|
||||
```go
|
||||
p := shellwords.NewParser()
|
||||
p.ParseBacktick = true
|
||||
args, err := p.Parse("./foo `echo $SHELL`")
|
||||
// args should be ["./foo", "/bin/bash"]
|
||||
```
|
||||
|
||||
```go
|
||||
shellwords.ParseBacktick = true
|
||||
p := shellwords.NewParser()
|
||||
args, err := p.Parse("./foo `echo $SHELL`")
|
||||
// args should be ["./foo", "/bin/bash"]
|
||||
```
|
||||
|
||||
# Thanks
|
||||
|
||||
This is based on cpan module [Parse::CommandLine](https://metacpan.org/pod/Parse::CommandLine).
|
||||
|
||||
# License
|
||||
|
||||
under the MIT License: http://mattn.mit-license.org/2017
|
||||
|
||||
# Author
|
||||
|
||||
Yasuhiro Matsumoto (a.k.a mattn)
|
||||
189
cmd/micro/shellwords/shellwords.go
Normal file
189
cmd/micro/shellwords/shellwords.go
Normal file
@@ -0,0 +1,189 @@
|
||||
package shellwords
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var envRe = regexp.MustCompile(`\$({[a-zA-Z0-9_]+}|[a-zA-Z0-9_]+)`)
|
||||
|
||||
func isSpace(r rune) bool {
|
||||
switch r {
|
||||
case ' ', '\t', '\r', '\n':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func replaceEnv(s string) string {
|
||||
return envRe.ReplaceAllStringFunc(s, func(s string) string {
|
||||
s = s[1:]
|
||||
if s[0] == '{' {
|
||||
s = s[1 : len(s)-1]
|
||||
}
|
||||
return os.Getenv(s)
|
||||
})
|
||||
}
|
||||
|
||||
type Parser struct {
|
||||
Position int
|
||||
}
|
||||
|
||||
func NewParser() *Parser {
|
||||
return &Parser{0}
|
||||
}
|
||||
|
||||
func (p *Parser) Parse(line string) ([]string, error) {
|
||||
args := []string{}
|
||||
buf := ""
|
||||
var escaped, doubleQuoted, singleQuoted, backQuote, dollarQuote bool
|
||||
backtick := ""
|
||||
|
||||
pos := -1
|
||||
got := false
|
||||
|
||||
loop:
|
||||
for i, r := range line {
|
||||
if escaped {
|
||||
buf += string(r)
|
||||
escaped = false
|
||||
continue
|
||||
}
|
||||
|
||||
if r == '\\' {
|
||||
if singleQuoted {
|
||||
buf += string(r)
|
||||
} else {
|
||||
escaped = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if isSpace(r) {
|
||||
if singleQuoted || doubleQuoted || backQuote || dollarQuote {
|
||||
buf += string(r)
|
||||
backtick += string(r)
|
||||
} else if got {
|
||||
buf = replaceEnv(buf)
|
||||
args = append(args, buf)
|
||||
buf = ""
|
||||
got = false
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
switch r {
|
||||
case '`':
|
||||
if !singleQuoted && !doubleQuoted && !dollarQuote {
|
||||
if backQuote {
|
||||
out, err := shellRun(backtick)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf = out
|
||||
}
|
||||
backtick = ""
|
||||
backQuote = !backQuote
|
||||
continue
|
||||
backtick = ""
|
||||
backQuote = !backQuote
|
||||
}
|
||||
case ')':
|
||||
if !singleQuoted && !doubleQuoted && !backQuote {
|
||||
if dollarQuote {
|
||||
out, err := shellRun(backtick)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf = out
|
||||
}
|
||||
backtick = ""
|
||||
dollarQuote = !dollarQuote
|
||||
continue
|
||||
backtick = ""
|
||||
dollarQuote = !dollarQuote
|
||||
}
|
||||
case '(':
|
||||
if !singleQuoted && !doubleQuoted && !backQuote {
|
||||
if !dollarQuote && len(buf) > 0 && buf == "$" {
|
||||
dollarQuote = true
|
||||
buf += "("
|
||||
continue
|
||||
} else {
|
||||
return nil, errors.New("invalid command line string")
|
||||
}
|
||||
}
|
||||
case '"':
|
||||
if !singleQuoted && !dollarQuote {
|
||||
doubleQuoted = !doubleQuoted
|
||||
continue
|
||||
}
|
||||
case '\'':
|
||||
if !doubleQuoted && !dollarQuote {
|
||||
singleQuoted = !singleQuoted
|
||||
continue
|
||||
}
|
||||
case ';', '&', '|', '<', '>':
|
||||
if !(escaped || singleQuoted || doubleQuoted || backQuote) {
|
||||
pos = i
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
got = true
|
||||
buf += string(r)
|
||||
if backQuote || dollarQuote {
|
||||
backtick += string(r)
|
||||
}
|
||||
}
|
||||
|
||||
buf = replaceEnv(buf)
|
||||
args = append(args, buf)
|
||||
|
||||
if escaped || singleQuoted || doubleQuoted || backQuote || dollarQuote {
|
||||
return nil, errors.New("invalid command line string")
|
||||
}
|
||||
|
||||
p.Position = pos
|
||||
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func Split(line string) ([]string, error) {
|
||||
return NewParser().Parse(line)
|
||||
}
|
||||
|
||||
func Join(args ...string) string {
|
||||
var buf bytes.Buffer
|
||||
for i, w := range args {
|
||||
if i != 0 {
|
||||
buf.WriteByte(' ')
|
||||
}
|
||||
if w == "" {
|
||||
buf.WriteString("''")
|
||||
continue
|
||||
}
|
||||
|
||||
for _, b := range w {
|
||||
switch b {
|
||||
case 'a', 'b', 'c', 'd', 'e', 'f', 'g',
|
||||
'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u',
|
||||
'v', 'w', 'x', 'y', 'z',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
||||
'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
||||
'O', 'P', 'Q', 'R', 'S', 'T', 'U',
|
||||
'V', 'W', 'X', 'Y', 'Z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'_', '-', '.', ',', ':', '/', '@':
|
||||
buf.WriteString(string(b))
|
||||
default:
|
||||
buf.WriteByte('\\')
|
||||
buf.WriteString(string(b))
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
229
cmd/micro/shellwords/shellwords_test.go
Normal file
229
cmd/micro/shellwords/shellwords_test.go
Normal file
@@ -0,0 +1,229 @@
|
||||
package shellwords
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testcases = []struct {
|
||||
line string
|
||||
expected []string
|
||||
}{
|
||||
{`var --bar=baz`, []string{`var`, `--bar=baz`}},
|
||||
{`var --bar="baz"`, []string{`var`, `--bar=baz`}},
|
||||
{`var "--bar=baz"`, []string{`var`, `--bar=baz`}},
|
||||
{`var "--bar='baz'"`, []string{`var`, `--bar='baz'`}},
|
||||
{"var --bar=`baz`", []string{`var`, "--bar=`baz`"}},
|
||||
{`var "--bar=\"baz'"`, []string{`var`, `--bar="baz'`}},
|
||||
{`var "--bar=\'baz\'"`, []string{`var`, `--bar='baz'`}},
|
||||
{`var --bar='\'`, []string{`var`, `--bar=\`}},
|
||||
{`var "--bar baz"`, []string{`var`, `--bar baz`}},
|
||||
{`var --"bar baz"`, []string{`var`, `--bar baz`}},
|
||||
{`var --"bar baz"`, []string{`var`, `--bar baz`}},
|
||||
}
|
||||
|
||||
func TestSimple(t *testing.T) {
|
||||
for _, testcase := range testcases {
|
||||
args, err := Parse(testcase.line)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(args, testcase.expected) {
|
||||
t.Fatalf("Expected %#v, but %#v:", testcase.expected, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestError(t *testing.T) {
|
||||
_, err := Parse("foo '")
|
||||
if err == nil {
|
||||
t.Fatal("Should be an error")
|
||||
}
|
||||
_, err = Parse(`foo "`)
|
||||
if err == nil {
|
||||
t.Fatal("Should be an error")
|
||||
}
|
||||
|
||||
_, err = Parse("foo `")
|
||||
if err == nil {
|
||||
t.Fatal("Should be an error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLastSpace(t *testing.T) {
|
||||
args, err := Parse("foo bar\\ ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(args) != 2 {
|
||||
t.Fatal("Should have two elements")
|
||||
}
|
||||
if args[0] != "foo" {
|
||||
t.Fatal("1st element should be `foo`")
|
||||
}
|
||||
if args[1] != "bar " {
|
||||
t.Fatal("1st element should be `bar `")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBacktick(t *testing.T) {
|
||||
goversion, err := shellRun("go version")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
parser := NewParser()
|
||||
parser.ParseBacktick = true
|
||||
args, err := parser.Parse("echo `go version`")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected := []string{"echo", goversion}
|
||||
if !reflect.DeepEqual(args, expected) {
|
||||
t.Fatalf("Expected %#v, but %#v:", expected, args)
|
||||
}
|
||||
|
||||
args, err = parser.Parse(`echo $(echo foo)`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected = []string{"echo", "foo"}
|
||||
if !reflect.DeepEqual(args, expected) {
|
||||
t.Fatalf("Expected %#v, but %#v:", expected, args)
|
||||
}
|
||||
|
||||
parser.ParseBacktick = false
|
||||
args, err = parser.Parse(`echo $(echo "foo")`)
|
||||
expected = []string{"echo", `$(echo "foo")`}
|
||||
if !reflect.DeepEqual(args, expected) {
|
||||
t.Fatalf("Expected %#v, but %#v:", expected, args)
|
||||
}
|
||||
args, err = parser.Parse("echo $(`echo1)")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected = []string{"echo", "$(`echo1)"}
|
||||
if !reflect.DeepEqual(args, expected) {
|
||||
t.Fatalf("Expected %#v, but %#v:", expected, args)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBacktickError(t *testing.T) {
|
||||
parser := NewParser()
|
||||
parser.ParseBacktick = true
|
||||
_, err := parser.Parse("echo `go Version`")
|
||||
if err == nil {
|
||||
t.Fatal("Should be an error")
|
||||
}
|
||||
expected := "exit status 2:go: unknown subcommand \"Version\"\nRun 'go help' for usage.\n"
|
||||
if expected != err.Error() {
|
||||
t.Fatalf("Expected %q, but %q", expected, err.Error())
|
||||
}
|
||||
_, err = parser.Parse(`echo $(echo1)`)
|
||||
if err == nil {
|
||||
t.Fatal("Should be an error")
|
||||
}
|
||||
_, err = parser.Parse(`echo $(echo1`)
|
||||
if err == nil {
|
||||
t.Fatal("Should be an error")
|
||||
}
|
||||
_, err = parser.Parse(`echo $ (echo1`)
|
||||
if err == nil {
|
||||
t.Fatal("Should be an error")
|
||||
}
|
||||
_, err = parser.Parse(`echo (echo1`)
|
||||
if err == nil {
|
||||
t.Fatal("Should be an error")
|
||||
}
|
||||
_, err = parser.Parse(`echo )echo1`)
|
||||
if err == nil {
|
||||
t.Fatal("Should be an error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnv(t *testing.T) {
|
||||
os.Setenv("FOO", "bar")
|
||||
|
||||
parser := NewParser()
|
||||
parser.ParseEnv = true
|
||||
args, err := parser.Parse("echo $FOO")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected := []string{"echo", "bar"}
|
||||
if !reflect.DeepEqual(args, expected) {
|
||||
t.Fatalf("Expected %#v, but %#v:", expected, args)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoEnv(t *testing.T) {
|
||||
parser := NewParser()
|
||||
parser.ParseEnv = true
|
||||
args, err := parser.Parse("echo $BAR")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected := []string{"echo", ""}
|
||||
if !reflect.DeepEqual(args, expected) {
|
||||
t.Fatalf("Expected %#v, but %#v:", expected, args)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDupEnv(t *testing.T) {
|
||||
os.Setenv("FOO", "bar")
|
||||
os.Setenv("FOO_BAR", "baz")
|
||||
|
||||
parser := NewParser()
|
||||
parser.ParseEnv = true
|
||||
args, err := parser.Parse("echo $$FOO$")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected := []string{"echo", "$bar$"}
|
||||
if !reflect.DeepEqual(args, expected) {
|
||||
t.Fatalf("Expected %#v, but %#v:", expected, args)
|
||||
}
|
||||
|
||||
args, err = parser.Parse("echo $${FOO_BAR}$")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected = []string{"echo", "$baz$"}
|
||||
if !reflect.DeepEqual(args, expected) {
|
||||
t.Fatalf("Expected %#v, but %#v:", expected, args)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHaveMore(t *testing.T) {
|
||||
parser := NewParser()
|
||||
parser.ParseEnv = true
|
||||
|
||||
line := "echo foo; seq 1 10"
|
||||
args, err := parser.Parse(line)
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
expected := []string{"echo", "foo"}
|
||||
if !reflect.DeepEqual(args, expected) {
|
||||
t.Fatalf("Expected %#v, but %#v:", expected, args)
|
||||
}
|
||||
|
||||
if parser.Position == 0 {
|
||||
t.Fatalf("Commands should be remaining")
|
||||
}
|
||||
|
||||
line = string([]rune(line)[parser.Position+1:])
|
||||
args, err = parser.Parse(line)
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
expected = []string{"seq", "1", "10"}
|
||||
if !reflect.DeepEqual(args, expected) {
|
||||
t.Fatalf("Expected %#v, but %#v:", expected, args)
|
||||
}
|
||||
|
||||
if parser.Position > 0 {
|
||||
t.Fatalf("Commands should not be remaining")
|
||||
}
|
||||
}
|
||||
22
cmd/micro/shellwords/util_posix.go
Normal file
22
cmd/micro/shellwords/util_posix.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// +build !windows
|
||||
|
||||
package shellwords
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func shellRun(line string) (string, error) {
|
||||
shell := os.Getenv("SHELL")
|
||||
b, err := exec.Command(shell, "-c", line).Output()
|
||||
if err != nil {
|
||||
if eerr, ok := err.(*exec.ExitError); ok {
|
||||
b = eerr.Stderr
|
||||
}
|
||||
return "", errors.New(err.Error() + ":" + string(b))
|
||||
}
|
||||
return strings.TrimSpace(string(b)), nil
|
||||
}
|
||||
20
cmd/micro/shellwords/util_windows.go
Normal file
20
cmd/micro/shellwords/util_windows.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package shellwords
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func shellRun(line string) (string, error) {
|
||||
shell := os.Getenv("COMSPEC")
|
||||
b, err := exec.Command(shell, "/c", line).Output()
|
||||
if err != nil {
|
||||
if eerr, ok := err.(*exec.ExitError); ok {
|
||||
b = eerr.Stderr
|
||||
}
|
||||
return "", errors.New(err.Error() + ":" + string(b))
|
||||
}
|
||||
return strings.TrimSpace(string(b)), nil
|
||||
}
|
||||
@@ -14,6 +14,10 @@ type Statusline struct {
|
||||
|
||||
// Display draws the statusline to the screen
|
||||
func (sline *Statusline) Display() {
|
||||
if messenger.hasPrompt && !GetGlobalOption("infobar").(bool) {
|
||||
return
|
||||
}
|
||||
|
||||
// We'll draw the line at the lowest line in the view
|
||||
y := sline.view.Height + sline.view.y
|
||||
|
||||
@@ -39,12 +43,24 @@ func (sline *Statusline) Display() {
|
||||
file += " " + sline.view.Buf.Settings["fileformat"].(string)
|
||||
|
||||
rightText := ""
|
||||
if len(helpBinding) > 0 {
|
||||
rightText = helpBinding + " for help "
|
||||
if sline.view.Type == vtHelp {
|
||||
rightText = helpBinding + " to close help "
|
||||
if len(kmenuBinding) > 0 {
|
||||
if globalSettings["keymenu"].(bool) {
|
||||
rightText += kmenuBinding + ": hide bindings"
|
||||
} else {
|
||||
rightText += kmenuBinding + ": show bindings"
|
||||
}
|
||||
}
|
||||
if len(helpBinding) > 0 {
|
||||
if len(kmenuBinding) > 0 {
|
||||
rightText += ", "
|
||||
}
|
||||
if sline.view.Type == vtHelp {
|
||||
rightText += helpBinding + ": close help"
|
||||
} else {
|
||||
rightText += helpBinding + ": open help"
|
||||
}
|
||||
}
|
||||
rightText += " "
|
||||
|
||||
statusLineStyle := defStyle.Reverse(true)
|
||||
if style, ok := colorscheme["statusline"]; ok {
|
||||
|
||||
@@ -36,6 +36,9 @@ func NewTabFromView(v *View) *Tab {
|
||||
if globalSettings["infobar"].(bool) {
|
||||
t.tree.height--
|
||||
}
|
||||
if globalSettings["keymenu"].(bool) {
|
||||
t.tree.height -= 2
|
||||
}
|
||||
|
||||
t.Resize()
|
||||
|
||||
@@ -62,6 +65,9 @@ func (t *Tab) Resize() {
|
||||
if globalSettings["infobar"].(bool) {
|
||||
t.tree.height--
|
||||
}
|
||||
if globalSettings["keymenu"].(bool) {
|
||||
t.tree.height -= 2
|
||||
}
|
||||
|
||||
t.tree.ResizeSplits()
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
@@ -56,6 +55,7 @@ func Max(a, b int) int {
|
||||
return b
|
||||
}
|
||||
|
||||
// FSize gets the size of a file
|
||||
func FSize(f *os.File) int64 {
|
||||
fi, _ := f.Stat()
|
||||
// get the size
|
||||
@@ -246,6 +246,7 @@ func lcs(a, b string) string {
|
||||
return lcs
|
||||
}
|
||||
|
||||
// CommonSubstring gets a common substring among the inputs
|
||||
func CommonSubstring(arr ...string) string {
|
||||
commonStr := arr[0]
|
||||
|
||||
@@ -274,97 +275,6 @@ func ShortFuncName(i interface{}) string {
|
||||
return strings.TrimPrefix(runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name(), "main.(*View).")
|
||||
}
|
||||
|
||||
// SplitCommandArgs separates multiple command arguments which may be quoted.
|
||||
// The returned slice contains at least one string
|
||||
func SplitCommandArgs(input string) []string {
|
||||
var result []string
|
||||
var curQuote *bytes.Buffer
|
||||
|
||||
curArg := new(bytes.Buffer)
|
||||
escape := false
|
||||
|
||||
finishQuote := func() {
|
||||
if curQuote == nil {
|
||||
return
|
||||
}
|
||||
str := curQuote.String()
|
||||
if unquoted, err := strconv.Unquote(str); err == nil {
|
||||
str = unquoted
|
||||
}
|
||||
curArg.WriteString(str)
|
||||
curQuote = nil
|
||||
}
|
||||
|
||||
appendResult := func() {
|
||||
finishQuote()
|
||||
escape = false
|
||||
|
||||
str := curArg.String()
|
||||
result = append(result, str)
|
||||
curArg.Reset()
|
||||
}
|
||||
|
||||
for _, r := range input {
|
||||
if r == ' ' && curQuote == nil {
|
||||
appendResult()
|
||||
} else {
|
||||
runeHandled := false
|
||||
appendRuneToBuff := func() {
|
||||
if curQuote != nil {
|
||||
curQuote.WriteRune(r)
|
||||
} else {
|
||||
curArg.WriteRune(r)
|
||||
}
|
||||
runeHandled = true
|
||||
}
|
||||
|
||||
if r == '"' && curQuote == nil {
|
||||
curQuote = new(bytes.Buffer)
|
||||
appendRuneToBuff()
|
||||
} else {
|
||||
if curQuote != nil && !escape {
|
||||
if r == '"' {
|
||||
appendRuneToBuff()
|
||||
finishQuote()
|
||||
} else if r == '\\' {
|
||||
appendRuneToBuff()
|
||||
escape = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
if !runeHandled {
|
||||
appendRuneToBuff()
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
// ReplaceHome takes a path as input and replaces ~ at the start of the path with the user's
|
||||
// home directory. Does nothing if the path does not start with '~'.
|
||||
func ReplaceHome(path string) string {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -67,56 +66,6 @@ func TestIsWordChar(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
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{`halloWelt`}},
|
||||
{`"hallo" "Welt"`, []string{`hallo`, `Welt`}},
|
||||
{`\"`, []string{`\"`}},
|
||||
{`"foo`, []string{`"foo`}},
|
||||
{`"foo"`, []string{`foo`}},
|
||||
{`"\"`, []string{`"\"`}},
|
||||
{`"C:\\"foo.txt`, []string{`C:\foo.txt`}},
|
||||
{`"\n"new"\n"line`, []string{"\nnew\nline"}},
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringWidth(t *testing.T) {
|
||||
tabsize := 4
|
||||
if w := StringWidth("1\t2", tabsize); w != 5 {
|
||||
|
||||
2
cmd/micro/vendor/github.com/zyedidia/tcell
generated
vendored
2
cmd/micro/vendor/github.com/zyedidia/tcell
generated
vendored
Submodule cmd/micro/vendor/github.com/zyedidia/tcell updated: c47e75564a...c92e80b717
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/zyedidia/tcell"
|
||||
)
|
||||
|
||||
// The ViewType defines what kind of view this is
|
||||
type ViewType struct {
|
||||
kind int
|
||||
readonly bool // The file cannot be edited
|
||||
@@ -61,7 +62,7 @@ type View struct {
|
||||
// The buffer
|
||||
Buf *Buffer
|
||||
// The statusline
|
||||
sline Statusline
|
||||
sline *Statusline
|
||||
|
||||
// Since tcell doesn't differentiate between a mouse release event
|
||||
// and a mouse move event with no keys pressed, we need to keep
|
||||
@@ -91,6 +92,8 @@ type View struct {
|
||||
cellview *CellView
|
||||
|
||||
splitNode *LeafNode
|
||||
|
||||
scrollbar *ScrollBar
|
||||
}
|
||||
|
||||
// NewView returns a new fullscreen view
|
||||
@@ -116,7 +119,11 @@ func NewViewWidthHeight(buf *Buffer, w, h int) *View {
|
||||
|
||||
v.messages = make(map[string][]GutterMessage)
|
||||
|
||||
v.sline = Statusline{
|
||||
v.sline = &Statusline{
|
||||
view: v,
|
||||
}
|
||||
|
||||
v.scrollbar = &ScrollBar{
|
||||
view: v,
|
||||
}
|
||||
|
||||
@@ -210,15 +217,12 @@ func (v *View) CanClose() bool {
|
||||
//if char == 'y' {
|
||||
if choice {
|
||||
v.Save(true)
|
||||
return true
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
// OpenBuffer opens a new buffer in this view.
|
||||
@@ -284,7 +288,7 @@ func (v *View) ReOpen() {
|
||||
// HSplit opens a horizontal split with the given buffer
|
||||
func (v *View) HSplit(buf *Buffer) {
|
||||
i := 0
|
||||
if v.Buf.Settings["splitBottom"].(bool) {
|
||||
if v.Buf.Settings["splitbottom"].(bool) {
|
||||
i = 1
|
||||
}
|
||||
v.splitNode.HSplit(buf, v.Num+i)
|
||||
@@ -293,7 +297,7 @@ func (v *View) HSplit(buf *Buffer) {
|
||||
// VSplit opens a vertical split with the given buffer
|
||||
func (v *View) VSplit(buf *Buffer) {
|
||||
i := 0
|
||||
if v.Buf.Settings["splitRight"].(bool) {
|
||||
if v.Buf.Settings["splitright"].(bool) {
|
||||
i = 1
|
||||
}
|
||||
v.splitNode.VSplit(buf, v.Num+i)
|
||||
@@ -449,6 +453,7 @@ func (v *View) MoveToMouseClick(x, y int) {
|
||||
v.Cursor.LastVisualX = v.Cursor.GetVisualX()
|
||||
}
|
||||
|
||||
// Execute actions executes the supplied actions
|
||||
func (v *View) ExecuteActions(actions []func(*View, bool) bool) bool {
|
||||
relocate := false
|
||||
readonlyBindingsList := []string{"Delete", "Insert", "Backspace", "Cut", "Play", "Paste", "Move", "Add", "DuplicateLine", "Macro"}
|
||||
@@ -478,6 +483,7 @@ func (v *View) ExecuteActions(actions []func(*View, bool) bool) bool {
|
||||
return relocate
|
||||
}
|
||||
|
||||
// SetCursor sets the view's and buffer's cursor
|
||||
func (v *View) SetCursor(c *Cursor) bool {
|
||||
if c == nil {
|
||||
return false
|
||||
@@ -497,6 +503,24 @@ func (v *View) HandleEvent(event tcell.Event) {
|
||||
v.Buf.CheckModTime()
|
||||
|
||||
switch e := event.(type) {
|
||||
case *tcell.EventRaw:
|
||||
for key, actions := range bindings {
|
||||
if key.keyCode == -1 {
|
||||
if e.EscapeCode() == key.escape {
|
||||
for _, c := range v.Buf.cursors {
|
||||
ok := v.SetCursor(c)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
relocate = false
|
||||
relocate = v.ExecuteActions(actions) || relocate
|
||||
}
|
||||
v.SetCursor(&v.Buf.Cursor)
|
||||
v.Buf.MergeCursors()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
case *tcell.EventKey:
|
||||
// Check first if input is a key binding, if it is we 'eat' the input and don't insert a rune
|
||||
isBinding := false
|
||||
@@ -682,6 +706,7 @@ func (v *View) openHelp(helpPage string) {
|
||||
}
|
||||
}
|
||||
|
||||
// DisplayView draws the view to the screen
|
||||
func (v *View) DisplayView() {
|
||||
if v.Buf.Settings["softwrap"].(bool) && v.leftCol != 0 {
|
||||
v.leftCol = 0
|
||||
@@ -989,6 +1014,11 @@ func (v *View) Display() {
|
||||
screen.HideCursor()
|
||||
}
|
||||
_, screenH := screen.Size()
|
||||
|
||||
if v.Buf.Settings["scrollbar"].(bool) {
|
||||
v.scrollbar.Display()
|
||||
}
|
||||
|
||||
if v.Buf.Settings["statusline"].(bool) {
|
||||
v.sline.Display()
|
||||
} else if (v.y + v.Height) != screenH-1 {
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component>
|
||||
<id>com.github.zyedidia.micro</id>
|
||||
<name>Micro Text Editor</name>
|
||||
<summary>A modern and intuitive terminal-based text editor</summary>
|
||||
<url type="homepage">https://micro-editor.github.io</url>
|
||||
<url type="bugtracker">https://github.com/zyedidia/micro</url>
|
||||
<metadata_license>MIT</metadata_license>
|
||||
<categories>
|
||||
<category>Development</category>
|
||||
<category>TextEditor</category>
|
||||
</categories>
|
||||
|
||||
<provides>
|
||||
<binary>micro</binary>
|
||||
</provides>
|
||||
<releases>
|
||||
<release version="1.2.0" date="2017-05-28" />
|
||||
</releases>
|
||||
<developer_name>Zachary Yedidia</developer_name>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<caption>Micro Text Editor editing its source code.</caption>
|
||||
<image type="source">https://raw.githubusercontent.com/zyedidia/micro/master/assets/micro-solarized.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<id>com.github.zyedidia.micro</id>
|
||||
<name>Micro Text Editor</name>
|
||||
<summary>A modern and intuitive terminal-based text editor</summary>
|
||||
<metadata_license>MIT</metadata_license>
|
||||
<categories>
|
||||
<category>Development</category>
|
||||
<category>TextEditor</category>
|
||||
</categories>
|
||||
<provides>
|
||||
<binary>micro</binary>
|
||||
</provides>
|
||||
<developer_name>Zachary Yedidia</developer_name>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<caption>Micro Text Editor editing its source code.</caption>
|
||||
<image type="source">https://raw.githubusercontent.com/zyedidia/micro/master/assets/micro-solarized.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<url type="homepage">https://micro-editor.github.io</url>
|
||||
<url type="bugtracker">https://github.com/zyedidia/micro/issues</url>
|
||||
</component>
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#Flamepoint theme
|
||||
#By CaptainMcClellan
|
||||
color-link default ""
|
||||
color-link comment ""
|
||||
color-link constant ""
|
||||
color-link constant.bool ""
|
||||
color-link constant.bool.true ""
|
||||
color-link constant.bool.false ""
|
||||
color-link constant.number ""
|
||||
color-link constant.specialChar ""
|
||||
color-link constant.string ""
|
||||
color-link constant.string.url "underline"
|
||||
color-link identifier ""
|
||||
color-link identifier.var ""
|
||||
color-link preproc ""
|
||||
color-link special ""
|
||||
color-link statement ""
|
||||
color-link symbol ""
|
||||
color-link symbol.brackets ""
|
||||
color-link symbol.tag ""
|
||||
color-link type ""
|
||||
color-link type.keyword ""
|
||||
color-link error ""
|
||||
color-link todo ""
|
||||
color-link cursor-line ""
|
||||
color-link statusline ""
|
||||
color-link tabbar ""
|
||||
color-link color-column ""
|
||||
color-link gutter-error ""
|
||||
color-link gutter-warning ""
|
||||
@@ -1 +0,0 @@
|
||||
#Funky Cactus theme in true colour.
|
||||
@@ -1,30 +0,0 @@
|
||||
#NES
|
||||
#A color theme only using NES pallette colours
|
||||
color-link default ""
|
||||
color-link comment ""
|
||||
color-link constant ""
|
||||
color-link constant.bool ""
|
||||
color-link constant.bool.true ""
|
||||
color-link constant.bool.false ""
|
||||
color-link constant.number ""
|
||||
color-link constant.specialChar ""
|
||||
color-link constant.string ""
|
||||
color-link constant.string.url "underline"
|
||||
color-link identifier ""
|
||||
color-link identifier.var ""
|
||||
color-link preproc ""
|
||||
color-link special ""
|
||||
color-link statement ""
|
||||
color-link symbol ""
|
||||
color-link symbol.brackets ""
|
||||
color-link symbol.tag ""
|
||||
color-link type ""
|
||||
color-link type.keyword ""
|
||||
color-link error ""
|
||||
color-link todo ""
|
||||
color-link cursor-line ""
|
||||
color-link statusline ""
|
||||
color-link tabbar ""
|
||||
color-link color-column ""
|
||||
color-link gutter-error ""
|
||||
color-link gutter-warning ""
|
||||
32
runtime/colorschemes/twilight.micro
Normal file
32
runtime/colorschemes/twilight.micro
Normal file
@@ -0,0 +1,32 @@
|
||||
# Twilight color scheme
|
||||
color-link default "#F8F8F8,#141414"
|
||||
color-link color-column "#1B1B1B"
|
||||
color-link comment "#5F5A60"
|
||||
color-link constant "#CF6A4C"
|
||||
#color-link constant.number "#CF6A4C"
|
||||
color-link constant.specialChar "#DDF2A4"
|
||||
color-link constant.string "#8F9D6A"
|
||||
color-link current-line-number "#868686,#1B1B1B"
|
||||
color-link cursor-line "#1B1B1B"
|
||||
color-link divider "#1E1E1E"
|
||||
color-link error "#D2A8A1"
|
||||
color-link gutter-error "#9B859D"
|
||||
color-link gutter-warning "#9B859D"
|
||||
color-link identifier "#9B703F"
|
||||
color-link identifier.class "#DAD085"
|
||||
color-link identifier.var "#7587A6"
|
||||
color-link indent-char "#515151"
|
||||
color-link line-number "#868686"
|
||||
color-link preproc "#E0C589"
|
||||
color-link special "#E0C589"
|
||||
color-link statement "#CDA869"
|
||||
color-link statusline "#515151,#1E1E1E"
|
||||
color-link symbol "#AC885B"
|
||||
color-link symbol.brackets "#F8F8F8"
|
||||
color-link symbol.operator "#CDA869"
|
||||
color-link symbol.tag "#AC885B"
|
||||
color-link tabbar "#F2F0EC,#2D2D2D"
|
||||
color-link todo "#8B98AB"
|
||||
color-link type "#F9EE98"
|
||||
color-link type.keyword "#CDA869"
|
||||
color-link underlined "#8996A8"
|
||||
@@ -5,79 +5,85 @@ This help page aims to cover two aspects of micro's syntax highlighting engine:
|
||||
- How to create colorschemes and use them
|
||||
- How to create syntax files to add to the list of languages micro can highlight
|
||||
|
||||
|
||||
## Colorschemes
|
||||
|
||||
Micro comes with a number of colorschemes by default. Here is the list:
|
||||
|
||||
* simple: this is the simplest colorscheme. It uses 16 colors which are
|
||||
set by your terminal
|
||||
* simple: this is the simplest colorscheme. It uses 16 colors which are set by
|
||||
your terminal
|
||||
|
||||
* mc: A 16-color theme based on the look and feel of GNU Midnight Commander.
|
||||
This will look great used in conjunction with Midnight Commander.
|
||||
|
||||
* nano: A 16-color theme loosely based on GNU nano's syntax highlighting.
|
||||
|
||||
* monokai: this is the monokai colorscheme; you may recognize it as
|
||||
Sublime Text's default colorscheme. It requires true color to
|
||||
look perfect, but the 256 color approximation looks very good as well.
|
||||
It's also the default colorscheme.
|
||||
* monokai: this is the monokai colorscheme; you may recognize it as Sublime
|
||||
Text's default colorscheme. It requires true color to look perfect, but the
|
||||
256 color approximation looks very good as well. It's also the default
|
||||
colorscheme.
|
||||
|
||||
* zenburn: The 'zenburn' colorscheme and works well with 256 color terminals
|
||||
|
||||
* solarized: this is the solarized colorscheme.
|
||||
You should have the solarized color palette in your terminal to use it.
|
||||
* solarized: this is the solarized colorscheme. You should have the solarized
|
||||
color palette in your terminal to use it.
|
||||
|
||||
* solarized-tc: this is the solarized colorscheme for true color; just
|
||||
make sure your terminal supports true color before using it and that the
|
||||
MICRO_TRUECOLOR environment variable is set to 1 before starting micro.
|
||||
* solarized-tc: this is the solarized colorscheme for true color; just make sure
|
||||
your terminal supports true color before using it and that the MICRO_TRUECOLOR
|
||||
environment variable is set to 1 before starting micro.
|
||||
|
||||
* atom-dark-tc: this colorscheme is based off of Atom's "dark" colorscheme.
|
||||
It requires true color to look good.
|
||||
* atom-dark-tc: this colorscheme is based off of Atom's "dark" colorscheme. It
|
||||
requires true color to look good.
|
||||
|
||||
* cmc-16: A very nice 16-color theme. Written by contributor CaptainMcClellan
|
||||
(Collin Warren.) Licensed under the same license as the rest of the themes.
|
||||
|
||||
* cmc-paper: Basically cmc-16, but on a white background. ( Actually light grey on most
|
||||
ANSI (16-color) terminals.)
|
||||
* cmc-paper: Basically cmc-16, but on a white background. (Actually light grey
|
||||
on most ANSI (16-color) terminals)
|
||||
|
||||
* cmc-tc: A true colour variant of the cmc theme.
|
||||
It requires true color to look its best. Use cmc-16 if your terminal doesn't support true color.
|
||||
* cmc-tc: A true colour variant of the cmc theme. It requires true color to
|
||||
look its best. Use cmc-16 if your terminal doesn't support true color.
|
||||
|
||||
* codeblocks: A colorscheme based on the Code::Blocks IDE's default syntax highlighting.
|
||||
* codeblocks: A colorscheme based on the Code::Blocks IDE's default syntax
|
||||
highlighting.
|
||||
|
||||
* codeblocks-paper: Same as codeblocks, but on a white background. ( Actually light grey. )
|
||||
* codeblocks-paper: Same as codeblocks, but on a white background. (Actually
|
||||
light grey)
|
||||
|
||||
* github-tc: A colorscheme based on Github's syntax highlighting. Requires true color to look its best.
|
||||
* github-tc: A colorscheme based on Github's syntax highlighting. Requires true
|
||||
color to look its best.
|
||||
|
||||
* paper-tc: A nice minimalist theme with a light background, good for editing documents on.
|
||||
Requires true color to look its best. Not to be confused with `-paper` suffixed themes.
|
||||
* paper-tc: A nice minimalist theme with a light background, good for editing
|
||||
documents on. Requires true color to look its best. Not to be confused with
|
||||
`-paper` suffixed themes.
|
||||
|
||||
* geany: Colorscheme based on geany's default highlighting.
|
||||
|
||||
* geany-alt-tc: Based on an alternate theme bundled with geany.
|
||||
|
||||
* flamepoint-tc: A fire inspired, high intensity true color theme written by CaptainMcClellan.
|
||||
As with all the other `-tc` suffixed themes, it looks its best on a
|
||||
* flamepoint-tc: A fire inspired, high intensity true color theme written by
|
||||
CaptainMcClellan. As with all the other `-tc` suffixed themes, it looks its
|
||||
best on a
|
||||
|
||||
To enable one of these colorschemes just press CtrlE in micro and type `set colorscheme solarized`.
|
||||
(or whichever one you choose). You can also use `set colorscheme monochrome` if you'd prefer
|
||||
to have just the terminal's default foreground and background colors.
|
||||
Note: This provides no syntax highlighting!
|
||||
To enable one of these colorschemes just press CtrlE in micro and type
|
||||
`set colorscheme solarized`. (or whichever one you choose). You can also use
|
||||
`set colorscheme monochrome` if you'd prefer to have just the terminal's default
|
||||
foreground and background colors. Note: This provides no syntax highlighting!
|
||||
|
||||
See `help gimmickcolors` for a list of some true colour themes that are more
|
||||
just for fun than for serious use. ( Though feel free if you want! )
|
||||
just for fun than for serious use. (Though feel free if you want!)
|
||||
|
||||
---
|
||||
|
||||
### Creating a Colorscheme
|
||||
## Creating a Colorscheme
|
||||
|
||||
Micro's colorschemes are also extremely simple to create. The default ones can be found
|
||||
Micro's colorschemes are also extremely simple to create. The default ones ca
|
||||
be found
|
||||
[here](https://github.com/zyedidia/micro/tree/master/runtime/colorschemes).
|
||||
|
||||
They are only about 18-30 lines in total.
|
||||
|
||||
Basically to create the colorscheme you need to link highlight groups with actual colors.
|
||||
This is done using the `color-link` command.
|
||||
Basically to create the colorscheme you need to link highlight groups with
|
||||
actual colors. This is done using the `color-link` command.
|
||||
|
||||
For example, to highlight all comments in green, you would use the command:
|
||||
|
||||
@@ -109,20 +115,22 @@ color-link comment "bold red"
|
||||
|
||||
There are three different ways to specify the color.
|
||||
|
||||
Color terminals usually have 16 colors that are preset by the user. This means that
|
||||
you cannot depend on those colors always being the same. You can use those colors with
|
||||
the names `black, red, green, yellow, blue, magenta, cyan, white` and the bright variants
|
||||
of each one (brightblack, brightred...).
|
||||
Color terminals usually have 16 colors that are preset by the user. This means
|
||||
that you cannot depend on those colors always being the same. You can use those
|
||||
colors with the names `black, red, green, yellow, blue, magenta, cyan, white`
|
||||
and the bright variants of each one (brightblack, brightred...).
|
||||
|
||||
Then you can use the terminals 256 colors by using their numbers 1-256 (numbers 1-16 will
|
||||
refer to the named colors).
|
||||
Then you can use the terminals 256 colors by using their numbers 1-256 (numbers
|
||||
1-16 will refer to the named colors).
|
||||
|
||||
If the user's terminal supports true color, then you can also specify colors exactly using
|
||||
their hex codes. If the terminal is not true color but micro is told to use a true color colorscheme
|
||||
it will attempt to map the colors to the available 256 colors.
|
||||
If the user's terminal supports true color, then you can also specify colors
|
||||
exactly using their hex codes. If the terminal is not true color but micro is
|
||||
told to use a true color colorscheme it will attempt to map the colors to the
|
||||
available 256 colors.
|
||||
|
||||
Generally colorschemes which require true color terminals to look good are marked with a `-tc` suffix
|
||||
and colorschemes which supply a white background are marked with a `-paper` suffix.
|
||||
Generally colorschemes which require true color terminals to look good are
|
||||
marked with a `-tc` suffix and colorschemes which supply a white background are
|
||||
marked with a `-paper` suffix.
|
||||
|
||||
---
|
||||
|
||||
@@ -140,9 +148,10 @@ Here is a list of the colorscheme groups that you can use:
|
||||
* underlined
|
||||
* error
|
||||
* todo
|
||||
* statusline ( Color of the statusline)
|
||||
* tabbar ( Color of the tabbar that lists open files.)
|
||||
* indent-char ( Color of the character which indicates tabs if the option is enabled)
|
||||
* statusline (Color of the statusline)
|
||||
* tabbar (Color of the tabbar that lists open files)
|
||||
* indent-char (Color of the character which indicates tabs if the option is
|
||||
enabled)
|
||||
* line-number
|
||||
* gutter-error
|
||||
* gutter-warning
|
||||
@@ -150,29 +159,30 @@ Here is a list of the colorscheme groups that you can use:
|
||||
* current-line-number
|
||||
* color-column
|
||||
* ignore
|
||||
* divider ( Color of the divider between vertical splits. )
|
||||
* divider (Color of the divider between vertical splits)
|
||||
|
||||
Colorschemes must be placed in the `~/.config/micro/colorschemes` directory to be used.
|
||||
Colorschemes must be placed in the `~/.config/micro/colorschemes` directory to
|
||||
be used.
|
||||
|
||||
---
|
||||
|
||||
In addition to the main colorscheme groups, there are subgroups that you can
|
||||
specify by adding `.subgroup` to the group. If you're creating your own
|
||||
custom syntax files, you can make use of your own subgroups.
|
||||
specify by adding `.subgroup` to the group. If you're creating your own custom
|
||||
syntax files, you can make use of your own subgroups.
|
||||
|
||||
If micro can't match the subgroup, it'll default to the root group, so
|
||||
it's safe and recommended to use subgroups in your custom syntax files.
|
||||
If micro can't match the subgroup, it'll default to the root group, so it's
|
||||
safe and recommended to use subgroups in your custom syntax files.
|
||||
|
||||
For example if `constant.string` is found in your colorscheme, micro will
|
||||
use that for highlighting strings. If it's not found, it will use constant
|
||||
instead. Micro tries to match the largest set of groups it can find in the
|
||||
colorscheme definitions, so if, for examle `constant.bool.true` is found then
|
||||
micro will use that. If `constant.bool.true` is not found but `constant.bool`
|
||||
is found micro will use `constant.bool`. If not, it uses `constant`.
|
||||
For example if `constant.string` is found in your colorscheme, micro will us
|
||||
that for highlighting strings. If it's not found, it will use constant instead.
|
||||
Micro tries to match the largest set of groups it can find in the colorscheme
|
||||
definitions, so if, for examle `constant.bool.true` is found then micro will use
|
||||
that. If `constant.bool.true` is not found but `constant.bool` is found micro
|
||||
will use `constant.bool`. If not, it uses `constant`.
|
||||
|
||||
Here's a list of subgroups used in micro's built-in syntax files.
|
||||
|
||||
* comment.bright ( Some filetypes have distinctions between types of comments.)
|
||||
* comment.bright (Some filetypes have distinctions between types of comments)
|
||||
* constant.bool
|
||||
* constant.bool.true
|
||||
* constant.bool.false
|
||||
@@ -180,29 +190,32 @@ Here's a list of subgroups used in micro's built-in syntax files.
|
||||
* constant.specialChar
|
||||
* constant.string
|
||||
* constant.string.url
|
||||
* identifier.class ( Also used for functions. )
|
||||
* identifier.class (Also used for functions)
|
||||
* identifier.macro
|
||||
* identifier.var
|
||||
* preproc.shebang ( The #! at the beginning of a file that tells the os what script interpreter to use. )
|
||||
* symbol.brackets ( {}()[] and sometimes <> )
|
||||
* symbol.operator ( Color operator symbols differently. )
|
||||
* symbol.tag ( For html tags, among other things.)
|
||||
* type.keyword ( If you want a special highlight for keywords like `private` )
|
||||
* preproc.shebang (The #! at the beginning of a file that tells the os what
|
||||
script interpreter to use)
|
||||
* symbol.brackets (`{}()[]` and sometimes `<>`)
|
||||
* symbol.operator (Color operator symbols differently)
|
||||
* symbol.tag (For html tags, among other things)
|
||||
* type.keyword (If you want a special highlight for keywords like `private`)
|
||||
|
||||
In the future, plugins may also be able to use color groups for styling.
|
||||
|
||||
|
||||
## Syntax files
|
||||
|
||||
The syntax files is written in yaml-format and specify how to highlight languages.
|
||||
The syntax files is written in yaml-format and specify how to highlight
|
||||
languages.
|
||||
|
||||
Micro's builtin syntax highlighting tries very hard to be sane, sensible
|
||||
and provide ample coverage of the meaningful elements of a language. Micro has
|
||||
syntax files built int for over 100 languages now. However, there may be
|
||||
situations where you find Micro's highlighting to be insufficient or not to
|
||||
your liking. Good news is you can create syntax files (.micro extension), place them in
|
||||
`~/.config/micro/syntax` and Micro will use those instead.
|
||||
Micro's builtin syntax highlighting tries very hard to be sane, sensible and
|
||||
provide ample coverage of the meaningful elements of a language. Micro has
|
||||
syntax files built in for over 100 languages now! However, there may be
|
||||
situations where you find Micro's highlighting to be insufficient or not to your
|
||||
liking. The good news is that you can create your own syntax files, and place them
|
||||
in `~/.config/micro/syntax` and Micro will use those instead.
|
||||
|
||||
### Filetype defintion
|
||||
### Filetype definition
|
||||
|
||||
You must start the syntax file by declaring the filetype:
|
||||
|
||||
@@ -219,8 +232,9 @@ detect:
|
||||
filename: "\\.go$"
|
||||
```
|
||||
|
||||
Micro will match this regex against a given filename to detect the filetype. You may also
|
||||
provide an optional `header` regex that will check the first line of the file. For example:
|
||||
Micro will match this regex against a given filename to detect the filetype. You
|
||||
may also provide an optional `header` regex that will check the first line of
|
||||
the file. For example:
|
||||
|
||||
```
|
||||
detect:
|
||||
@@ -230,9 +244,10 @@ detect:
|
||||
|
||||
#### Syntax rules
|
||||
|
||||
Next you must provide the syntax highlighting rules. There are two types of rules: patterns and regions.
|
||||
A pattern is matched on a single line and usually a single word as well. A region highlights between two
|
||||
patterns over multiple lines and may have rules of its own inside the region.
|
||||
Next you must provide the syntax highlighting rules. There are two types of
|
||||
rules: patterns and regions. A pattern is matched on a single line and usually a
|
||||
single word as well. A region highlights between two patterns over multiple
|
||||
lines and may have rules of its own inside the region.
|
||||
|
||||
Here are some example patterns in Go:
|
||||
|
||||
@@ -243,7 +258,8 @@ rules:
|
||||
- preproc: "\\b(package|import|const|var|type|struct|func|go|defer|iota)\\b"
|
||||
```
|
||||
|
||||
The order of patterns does matter as patterns lower in the file will overwrite the ones defined above them.
|
||||
The order of patterns does matter as patterns lower in the file will overwrite
|
||||
the ones defined above them.
|
||||
|
||||
And here are some example regions for Go:
|
||||
|
||||
@@ -269,12 +285,15 @@ And here are some example regions for Go:
|
||||
- todo: "(TODO|XXX|FIXME):?"
|
||||
```
|
||||
|
||||
Notice how the regions may contain rules inside of them. Any inner rules that are matched are then skipped when searching
|
||||
for the end of the region. For example, when highlighting `"foo \" bar"`, since `\"` is matched by an inner rule in the
|
||||
region, it is skipped. Likewise for `"foo \\" bar`, since `\\` is matched by an inner rule, it is skipped, and then the `"`
|
||||
is found and the string ends at the correct place.
|
||||
Notice how the regions may contain rules inside of them. Any inner rules that
|
||||
are matched are then skipped when searching for the end of the region. For
|
||||
example, when highlighting `"foo \" bar"`, since `\"` is matched by an inner
|
||||
rule in the region, it is skipped. Likewise for `"foo \\" bar`, since `\\` is
|
||||
matched by an inner rule, it is skipped, and then the `"` is found and the
|
||||
string ends at the correct place.
|
||||
|
||||
You may also explicitly mark skip regexes if you don't want them to be highlighted. For example:
|
||||
You may also explicitly mark skip regexes if you don't want them to be
|
||||
highlighted. For example:
|
||||
|
||||
```
|
||||
- constant.string:
|
||||
@@ -286,8 +305,8 @@ You may also explicitly mark skip regexes if you don't want them to be highlight
|
||||
|
||||
#### Includes
|
||||
|
||||
You may also include rules from other syntax files as embedded languages. For example, the following is possible
|
||||
for html:
|
||||
You may also include rules from other syntax files as embedded languages. For
|
||||
example, the following is possible for html:
|
||||
|
||||
```
|
||||
- default:
|
||||
|
||||
@@ -5,24 +5,24 @@ Here are the possible commands that you can use.
|
||||
|
||||
* `quit`: Quits micro.
|
||||
|
||||
* `save filename?`: Saves the current buffer. If the filename is provided it will
|
||||
'save as' the filename.
|
||||
* `save filename?`: Saves the current buffer. If the filename is provided it
|
||||
will 'save as' the filename.
|
||||
|
||||
* `replace "search" "value" flags`: This will replace `search` with `value`.
|
||||
The `flags` are optional.
|
||||
At this point, there is only one flag: `-a`, which replaces all occurrences
|
||||
at once.
|
||||
The `flags` are optional. Possible flags are:
|
||||
* `-a`: Replace all occurrences at once
|
||||
* `-l`: Do a literal search instead of a regex search
|
||||
|
||||
Note that `search` must be a valid regex. If one of the arguments
|
||||
does not have any spaces in it, you may omit the quotes.
|
||||
Note that `search` must be a valid regex (unless `-l` is passed). If one
|
||||
of the arguments does not have any spaces in it, you may omit the quotes.
|
||||
|
||||
* `replaceall "search" "value"`: This will replace `search` with `value` without
|
||||
user confirmation.
|
||||
user confirmation.
|
||||
|
||||
See `replace` command for more information.
|
||||
See `replace` command for more information.
|
||||
|
||||
* `set option value`: sets the option to value. See the `options` help topic
|
||||
for a list of options you can set.
|
||||
* `set option value`: sets the option to value. See the `options` help topic for
|
||||
a list of options you can set.
|
||||
|
||||
* `setlocal option value`: sets the option to value locally (only in the current
|
||||
buffer).
|
||||
@@ -30,27 +30,25 @@ Here are the possible commands that you can use.
|
||||
* `show option`: shows the current value of the given option.
|
||||
|
||||
* `eval "expression"`: Evaluates a Lua expression. Note that micro will not
|
||||
print anything so you should use `messenger:Message(...)` to display a
|
||||
value.
|
||||
print anything so you should use `messenger:Message(...)` to display a value.
|
||||
|
||||
* `run sh-command`: runs the given shell command in the background. The
|
||||
command's output will be displayed in one line when it finishes running.
|
||||
|
||||
* `bind key action`: creates a keybinding from key to action. See the sections on
|
||||
keybindings above for more info about what keys and actions are available.
|
||||
* `bind key action`: creates a keybinding from key to action. See the sections
|
||||
on keybindings above for more info about what keys and actions are available.
|
||||
|
||||
* `vsplit filename`: opens a vertical split with `filename`. If no filename is
|
||||
provided, a vertical split is opened with an empty buffer.
|
||||
|
||||
* `hsplit filename`: same as `vsplit` but opens a horizontal split instead of
|
||||
a vertical split.
|
||||
* `hsplit filename`: same as `vsplit` but opens a horizontal split instead of a
|
||||
vertical split.
|
||||
|
||||
* `tab filename`: opens the given file in a new tab.
|
||||
|
||||
* `tabswitch tab`: This command will switch to the specified tab.
|
||||
The `tab` can either be a tab number, or a name of a tab.
|
||||
|
||||
|
||||
* `tabswitch tab`: This command will switch to the specified tab. The `tab` can
|
||||
either be a tab number, or a name of a tab.
|
||||
|
||||
* `log`: opens a log of all messages and debug statements.
|
||||
|
||||
* `plugin install plugin_name`: installs the given plugin.
|
||||
@@ -61,15 +59,15 @@ Here are the possible commands that you can use.
|
||||
|
||||
* `plugin update`: updates all installed plugins.
|
||||
|
||||
* `plugin search plugin_name`: searches for the given plugin.
|
||||
Note that you can find a list of all available plugins at
|
||||
* `plugin search plugin_name`: searches for the given plugin. Note that you can
|
||||
find a list of all available plugins at
|
||||
github.com/micro-editor/plugin-channel.
|
||||
|
||||
You can also see more information about the plugin manager
|
||||
in the `Plugin Manager` section of the `plugins` help topic.
|
||||
You can also see more information about the plugin manager in the
|
||||
`Plugin Manager` section of the `plugins` help topic.
|
||||
|
||||
* `plugin available`: list plugins available for download (this includes
|
||||
any plugins that may be already installed).
|
||||
* `plugin available`: list plugins available for download (this includes any
|
||||
plugins that may be already installed).
|
||||
|
||||
* `reload`: reloads all runtime files.
|
||||
|
||||
@@ -79,8 +77,19 @@ Here are the possible commands that you can use.
|
||||
|
||||
* `open filename`: Open a file in the current buffer.
|
||||
|
||||
* `retab`: Replaces all leading tabs with spaces or leading spaces with tabs
|
||||
depending on the value of `tabstospaces`.
|
||||
|
||||
---
|
||||
|
||||
The following commands are provided by the default plugins:
|
||||
|
||||
* `lint`: Lint the current file for errors.
|
||||
|
||||
# Command Parsing
|
||||
|
||||
When running a command, you can use extra syntax that micro will expand before
|
||||
running the command. To use an argument with a space in it, simply put it in
|
||||
quotes. You can also use environment variables in the command bar and they
|
||||
will be expanded to their value. Finally, you can put an expression in backticks
|
||||
and it will be evaluated by the shell beforehand.
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Default Keys
|
||||
|
||||
Below are simple charts of the default hotkeys and their functions.
|
||||
For more information about binding custom hotkeys or changing
|
||||
default bindings, please run `> help keybindings`
|
||||
Below are simple charts of the default hotkeys and their functions. For more
|
||||
information about binding custom hotkeys or changing default bindings, please
|
||||
run `> help keybindings`
|
||||
|
||||
Please remember that *all* keys here are rebindable!
|
||||
If you don't like it, you can change it!
|
||||
Please remember that *all* keys here are rebindable! If you don't like it, you
|
||||
can change it!
|
||||
|
||||
# Power user
|
||||
### Power user
|
||||
|
||||
| Key | Description of function |
|
||||
|-------- |-------------------------------------------------------------------------------------------------- |
|
||||
@@ -15,7 +15,7 @@ If you don't like it, you can change it!
|
||||
| Tab | In command prompt, it will autocomplete if possible. |
|
||||
| Ctrl+B | Run a shell command (this will close micro while your command executes). |
|
||||
|
||||
# Navigation
|
||||
### Navigation
|
||||
|
||||
| Key | Description of function |
|
||||
|-------------------------- |------------------------------------------------------------------------------------------ |
|
||||
@@ -25,6 +25,8 @@ If you don't like it, you can change it!
|
||||
| End or CtrlRightArrow | Move to the end of the current line |
|
||||
| AltLeftArrow | Move cursor one word left |
|
||||
| AltRightArrow | Move cursor one word right |
|
||||
| Alt+{ | Move cursor to previous empty line, or beginning of document |
|
||||
| Alt+} | Move cursor to next empty line, or end of document |
|
||||
| PageUp | Move cursor up one page |
|
||||
| PageDown | Move cursor down one page |
|
||||
| CtrlHome or CtrlUpArrow | Move cursor to start of document |
|
||||
@@ -32,7 +34,7 @@ If you don't like it, you can change it!
|
||||
| Ctrl+L | Jump to a line in the file (prompts with #) |
|
||||
| Ctrl+W | Cycle between splits in the current tab (use `> vsplit` or `> hsplit` to create a split) |
|
||||
|
||||
# Tabs
|
||||
### Tabs
|
||||
|
||||
| Key | Description of function |
|
||||
|-------- |------------------------- |
|
||||
@@ -40,7 +42,7 @@ If you don't like it, you can change it!
|
||||
| Alt+, | Previous tab |
|
||||
| Alt+. | Next tab |
|
||||
|
||||
# Find Operations
|
||||
### Find Operations
|
||||
|
||||
| Key | Description of function |
|
||||
|-------- |------------------------------------------ |
|
||||
@@ -48,7 +50,7 @@ If you don't like it, you can change it!
|
||||
| Ctrl+N | Find next instance of current search |
|
||||
| Ctrl+P | Find previous instance of current search |
|
||||
|
||||
# File Operations
|
||||
### File Operations
|
||||
|
||||
| Key | Description of function |
|
||||
|-------- |---------------------------------------------------------------- |
|
||||
@@ -56,7 +58,7 @@ If you don't like it, you can change it!
|
||||
| Ctrl+O | Open a file (prompts for filename) |
|
||||
| Ctrl+S | Save current file |
|
||||
|
||||
# Text operations
|
||||
### Text operations
|
||||
|
||||
| Key | Description of function |
|
||||
|--------------------------------- |------------------------------------------ |
|
||||
@@ -78,14 +80,14 @@ If you don't like it, you can change it!
|
||||
| AltBackspace or AltCtrl+H | Delete word left |
|
||||
| Ctrl+A | Select all |
|
||||
|
||||
# Macros
|
||||
### Macros
|
||||
|
||||
| Key | Description of function |
|
||||
|-------- |---------------------------------------------------------------------------------- |
|
||||
| Ctrl+U | Toggle macro recording (press Ctrl+U to start recording and press again to stop) |
|
||||
| Ctrl+J | Run latest recorded macro |
|
||||
|
||||
# Multiple cursors
|
||||
### Multiple cursors
|
||||
|
||||
| Key | Description of function |
|
||||
|---------------- |---------------------------------------------------------------------------------------------- |
|
||||
@@ -95,7 +97,7 @@ If you don't like it, you can change it!
|
||||
| Alt+X | Skip multiple cursor selection |
|
||||
| Ctrl-MouseLeft | Place a multiple cursor at any location |
|
||||
|
||||
# Other
|
||||
### Other
|
||||
|
||||
| Key | Description of function |
|
||||
|-------- |----------------------------------------------------------------------------------- |
|
||||
@@ -103,7 +105,7 @@ If you don't like it, you can change it!
|
||||
| Ctrl+H | Backspace (old terminals do not support the backspace key and use Ctrl+H instead) |
|
||||
| Ctrl+R | Toggle the line number ruler |
|
||||
|
||||
# Emacs style actions
|
||||
### Emacs style actions
|
||||
|
||||
| Key | Description of function |
|
||||
|------- |------------------------- |
|
||||
@@ -112,7 +114,7 @@ If you don't like it, you can change it!
|
||||
| Alt+A | Move to start of line |
|
||||
| Alt+E | Move to end of line |
|
||||
|
||||
# Function keys.
|
||||
### Function keys.
|
||||
|
||||
Warning! The function keys may not work in all terminals!
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ We have included a few colorschemes that are for fun:
|
||||
Nintendo Entertainment System color palette.
|
||||
* symbian-tc: Colorscheme based on SymbOS's GUI.
|
||||
* matrix: Pretend it's 1981 with a colorscheme based on a monochrome
|
||||
IBM 5151. ( Does not include the ghosting and trailing. )
|
||||
IBM 5151. (Does not include the ghosting and trailing)
|
||||
|
||||
Check the plugin repo periodically for gimmick-color extension packs
|
||||
and genuine additional themes.
|
||||
Check the plugin repo periodically for gimmick-color extension packs and genuine
|
||||
additional themes.
|
||||
@@ -1,6 +1,7 @@
|
||||
# Micro help text
|
||||
|
||||
Thank you for downloading and using micro.
|
||||
|
||||
Micro is a terminal-based text editor that aims to be easy to use and intuitive,
|
||||
while also taking advantage of the full capabilities of modern terminals.
|
||||
|
||||
@@ -8,44 +9,52 @@ 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.
|
||||
|
||||
### Quick-start
|
||||
|
||||
Press CtrlQ to quit, and CtrlS to save. Press CtrlE to start typing commands
|
||||
and you can see which commands are available by pressing tab, or by
|
||||
viewing the help topic `> help commands`. When I write `> ...` I mean press
|
||||
CtrlE and then type whatever is there.
|
||||
## Quick-start
|
||||
|
||||
Move the cursor around with the mouse or the arrow keys. Type `> help defaultkeys` to
|
||||
get a quick, easy overview of the default hotkeys and what they do. For more info
|
||||
on rebinding keys, see type `> help keybindings`
|
||||
Press CtrlQ to quit, and CtrlS to save. Press CtrlE to start typing commands and
|
||||
you can see which commands are available by pressing tab, or by viewing the help
|
||||
topic `> help commands`. When I write `> ...` I mean press Ctrl0E and then type
|
||||
whatever is there.
|
||||
|
||||
If the colorscheme doesn't look good, you can change it with `> set colorscheme ...`.
|
||||
You can press tab to see the available colorschemes, or see more information with
|
||||
`> help colors`.
|
||||
Move the cursor around with the mouse or the arrow keys. Type
|
||||
`> help defaultkeys` to get a quick, easy overview of the default hotkeys and
|
||||
what they do. For more info on rebinding keys, see type `> help keybindings`.
|
||||
|
||||
Press CtrlW to move between splits, and type `> vsplit filename` or `> hsplit filename`
|
||||
to open a new split.
|
||||
If the colorscheme doesn't look good, you can change it with
|
||||
`> set colorscheme ...`. You can press tab to see the available colorschemes, or
|
||||
see more information with `> help colors`.
|
||||
|
||||
### Accessing more help
|
||||
Press CtrlW to move between splits, and type `> vsplit filename` or
|
||||
`> hsplit filename` to open a new split.
|
||||
|
||||
|
||||
## Accessing more help
|
||||
|
||||
Micro has a built-in help system much like Vim's (although less extensive).
|
||||
|
||||
To use it, press CtrlE to access command mode and type in `help` followed by a topic.
|
||||
Typing `help` followed by nothing will open this page.
|
||||
To use it, press CtrlE to access command mode and type in `help` followed by a
|
||||
topic. Typing `help` followed by nothing will open this page.
|
||||
|
||||
Here are the possible help topics that you can read:
|
||||
|
||||
* tutorial: A brief tutorial which gives an overview of all the other help topics
|
||||
* keybindings: Gives a full list of the default keybindings as well as how to rebind them
|
||||
* defaultkeys: Gives a more straight-forward list of the hotkey commands and what they do.
|
||||
* tutorial: A brief tutorial which gives an overview of all the other help
|
||||
topics
|
||||
* keybindings: Gives a full list of the default keybindings as well as how to
|
||||
rebind them
|
||||
* defaultkeys: Gives a more straight-forward list of the hotkey commands and what
|
||||
they do.
|
||||
* commands: Gives a list of all the commands and what they do
|
||||
* options: Gives a list of all the options you can customize
|
||||
* plugins: Explains how micro's plugin system works and how to create your own plugins
|
||||
* colors: Explains micro's colorscheme and syntax highlighting engine and how to create your
|
||||
own colorschemes or add new languages to the engine
|
||||
* plugins: Explains how micro's plugin system works and how to create your own
|
||||
plugins
|
||||
* colors: Explains micro's colorscheme and syntax highlighting engine and how to
|
||||
create your own colorschemes or add new languages to the engine
|
||||
|
||||
For example, to open the help page on plugins you would press CtrlE and type `help plugins`.
|
||||
For example, to open the help page on plugins you would press CtrlE and type
|
||||
`help plugins`.
|
||||
|
||||
I recommend looking at the `tutorial` help file because it is short for each section and
|
||||
gives concrete examples of how to use the various configuration options in micro. However,
|
||||
it does not give the in-depth documentation that the other topics provide.
|
||||
I recommend looking at the `tutorial` help file because it is short for each
|
||||
section and gives concrete examples of how to use the various configuration
|
||||
options in micro. However, it does not give the in-depth documentation that the
|
||||
other topics provide.
|
||||
|
||||
@@ -2,25 +2,28 @@
|
||||
|
||||
Micro has a plethora of hotkeys that make it easy and powerful to use and all
|
||||
hotkeys are fully customizable to your liking.
|
||||
Custom keybindings are stored internally in micro if changed with the `>bind` command or
|
||||
you can also be added in the file `~/.config/micro/bindings.json` as discussed below.
|
||||
For a list of the default keybindings in the json format used by micro, please see
|
||||
the end of this file. For a more user-friendly list with explanations of what the default
|
||||
hotkeys are and what they do, please see `>help defaultkeys`
|
||||
|
||||
Custom keybindings are stored internally in micro if changed with the `> bind`
|
||||
command or you can also be added in the file `~/.config/micro/bindings.json` as
|
||||
discussed below. For a list of the default keybindings in the json format used
|
||||
by micro, please see the end of this file. For a more user-friendly list with
|
||||
explanations of what the default hotkeys are and what they do, please see
|
||||
`>help defaultkeys`
|
||||
|
||||
If `~/.config/micro/bindings.json` does not exist, you can simply create it.
|
||||
Micro will know what to do with it.
|
||||
|
||||
You can use the alt keys + arrows to move word by word.
|
||||
Ctrl left and right move the cursor to the start and end of the line, and
|
||||
ctrl up and down move the cursor the start and end of the buffer.
|
||||
You can use the alt keys + arrows to move word by word. Ctrl left and right move
|
||||
the cursor to the start and end of the line, and ctrl up and down move the
|
||||
cursor the start and end of the buffer.
|
||||
|
||||
You can hold shift with all of these movement actions to select while moving.
|
||||
|
||||
# Rebinding keys
|
||||
|
||||
The bindings may be rebound using the `~/.config/micro/bindings.json`
|
||||
file. Each key is bound to an action.
|
||||
## Rebinding keys
|
||||
|
||||
The bindings may be rebound using the `~/.config/micro/bindings.json` file. Each
|
||||
key is bound to an action.
|
||||
|
||||
For example, to bind `Ctrl-y` to undo and `Ctrl-z` to redo, you could put the
|
||||
following in the `bindings.json` file.
|
||||
@@ -35,8 +38,8 @@ following in the `bindings.json` file.
|
||||
In addition to editing your `~/.config/micro/bindings.json`, you can run
|
||||
`>bind <keycombo> <action>` For a list of bindable actions, see below.
|
||||
|
||||
You can also chain commands when rebinding. For example, if you want Alt-s to save
|
||||
and quit you can bind it like so:
|
||||
You can also chain commands when rebinding. For example, if you want Alt-s to
|
||||
save and quit you can bind it like so:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -44,12 +47,59 @@ and quit you can bind it like so:
|
||||
}
|
||||
```
|
||||
|
||||
# Unbinding keys
|
||||
|
||||
## Binding raw escape sequences
|
||||
|
||||
Only read this section if you are interested in binding keys that aren't on the
|
||||
list of supported keys for binding.
|
||||
|
||||
One of the drawbacks of using a terminal-based editor is that the editor must
|
||||
get all of its information about key events through the terminal. The terminal
|
||||
sends these events in the form of escape sequences often (but not always)
|
||||
starting with `0x1b`.
|
||||
|
||||
For example, if micro reads `\x1b[1;5D`, on most terminals this will mean the
|
||||
user pressed CtrlLeft.
|
||||
|
||||
For many key chords though, the terminal won't send any escape code or will send
|
||||
an escape code already in use. For example for `CtrlBackspace`, my terminal
|
||||
sends `\u007f` (note this doesn't start with `0x1b`), which it also sends for
|
||||
`Backspace` meaning micro can't bind `CtrlBackspace`.
|
||||
|
||||
However, some terminals do allow you to bind keys to send specific escape
|
||||
sequences you define. Then from micro you can directly bind those escape
|
||||
sequences to actions. For example, to bind `CtrlBackspace` you can instruct your
|
||||
terminal to send `\x1bctrlback` and then bind it in `bindings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"\u001bctrlback": "DeleteWordLeft"
|
||||
}
|
||||
```
|
||||
|
||||
Here are some instructions for sending raw escapes in different terminals
|
||||
|
||||
### iTerm2
|
||||
|
||||
In iTerm2, you can do this in `Preferences->Profiles->Keys` then click the `+`,
|
||||
input your keybinding, and for the `Action` select `Send Escape Sequence`. For
|
||||
the above example your would type `ctrlback` into the box (the `\x1b`) is
|
||||
automatically sent by iTerm2.
|
||||
|
||||
### Linux using loadkeys
|
||||
|
||||
You can do this in linux using the loadkeys program.
|
||||
|
||||
Coming soon!
|
||||
|
||||
|
||||
## Unbinding keys
|
||||
|
||||
It is also possible to disable any of the default key bindings by use of the
|
||||
`UnbindKey` action in the user's `bindings.json` file.
|
||||
|
||||
# Bindable actions and bindable keys
|
||||
|
||||
## Bindable actions and bindable keys
|
||||
|
||||
The list of default keybindings contains most of the possible actions and keys
|
||||
which you can use, but not all of them. Here is a full list of both.
|
||||
@@ -113,6 +163,8 @@ HalfPageUp
|
||||
HalfPageDown
|
||||
StartOfLine
|
||||
EndOfLine
|
||||
ParagraphPrevious
|
||||
ParagraphNext
|
||||
ToggleHelp
|
||||
ToggleRuler
|
||||
JumpLine
|
||||
@@ -142,6 +194,7 @@ UnbindKey
|
||||
```
|
||||
|
||||
You can also bind some mouse actions (these must be bound to mouse buttons)
|
||||
|
||||
```
|
||||
MousePress
|
||||
MouseMultiCursor
|
||||
@@ -275,7 +328,8 @@ Escape
|
||||
Enter
|
||||
```
|
||||
|
||||
You can also bind some mouse buttons (they may be bound to normal actions or mouse actions)
|
||||
You can also bind some mouse buttons (they may be bound to normal actions or
|
||||
mouse actions)
|
||||
|
||||
```
|
||||
MouseLeft
|
||||
@@ -315,6 +369,8 @@ MouseWheelRight
|
||||
"CtrlDown": "CursorEnd",
|
||||
"CtrlShiftUp": "SelectToStart",
|
||||
"CtrlShiftDown": "SelectToEnd",
|
||||
"Alt-{": "ParagraphPrevious",
|
||||
"Alt-}": "ParagraphNext",
|
||||
"Enter": "InsertNewline",
|
||||
"CtrlH": "Backspace",
|
||||
"Backspace": "Backspace",
|
||||
@@ -385,12 +441,13 @@ MouseWheelRight
|
||||
}
|
||||
```
|
||||
|
||||
# Final notes
|
||||
Note: On some old terminal emulators and on Windows machines, `CtrlH` should be used
|
||||
for backspace.
|
||||
## Final notes
|
||||
|
||||
Additionally, alt keys can be bound by using `Alt-key`. For example `Alt-a`
|
||||
or `Alt-Up`. Micro supports an optional `-` between modifiers like `Alt` and `Ctrl`
|
||||
so `Alt-a` could be rewritten as `Alta` (case matters for alt bindings). This is
|
||||
why in the default keybindings you can see `AltShiftLeft` instead of `Alt-ShiftLeft`
|
||||
(they are equivalent).
|
||||
Note: On some old terminal emulators and on Windows machines, `CtrlH` should be
|
||||
used for backspace.
|
||||
|
||||
Additionally, alt keys can be bound by using `Alt-key`. For example `Alt-a` or
|
||||
`Alt-Up`. Micro supports an optional `-` between modifiers like `Alt` and
|
||||
`Ctrl` so `Alt-a` could be rewritten as `Alta` (case matters for alt bindings).
|
||||
This is why in the default keybindings you can see `AltShiftLeft` instead of
|
||||
`Alt-ShiftLeft` (they are equivalent).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
### Options
|
||||
# Options
|
||||
|
||||
Micro stores all of the user configuration in its configuration directory.
|
||||
|
||||
@@ -8,11 +8,29 @@ the config directory.
|
||||
|
||||
Here are the options that you can set:
|
||||
|
||||
* `autoindent`: when creating a new line use the same indentation as the
|
||||
previous line.
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `autosave`: micro will save the buffer every 8 seconds automatically. Micro
|
||||
also will automatically save and quit when you exit without asking. Be
|
||||
careful when using this feature, because you might accidentally save a file,
|
||||
overwriting what was there before.
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `colorcolumn`: if this is not set to 0, it will display a column at the
|
||||
specified column. This is useful if you want column 80 to be highlighted
|
||||
special for example.
|
||||
|
||||
default value: `0`
|
||||
|
||||
* `colorscheme`: loads the colorscheme stored in
|
||||
$(configDir)/colorschemes/`option`.micro
|
||||
This setting is `global only`.
|
||||
$(configDir)/colorschemes/`option`.micro, This setting is `global only`.
|
||||
|
||||
default value: `default`
|
||||
|
||||
Note that the default colorschemes (default, solarized, and solarized-tc)
|
||||
are not located in configDir, because they are embedded in the micro binary.
|
||||
|
||||
@@ -20,178 +38,198 @@ Here are the options that you can set:
|
||||
~/.config/micro/colorschemes/ directory. Micro comes by default with three
|
||||
colorschemes:
|
||||
|
||||
You can read more about micro's colorschemes in the `colors` help topic
|
||||
(`help colors`).
|
||||
You can read more about micro's colorschemes in the `colors` help topic
|
||||
(`help colors`).
|
||||
|
||||
* `colorcolumn`: if this is not set to 0, it will display a column at the specified
|
||||
column. This is useful if you want column 80 to be highlighted special for example.
|
||||
* `cursorline`: highlight the line that the cursor is on in a different color
|
||||
(the color is defined by the colorscheme you are using).
|
||||
|
||||
default value: `0`
|
||||
default value: `on`
|
||||
|
||||
* `eofnewline`: micro will automatically add a newline to the file.
|
||||
|
||||
default value: `false`
|
||||
|
||||
* `fastdirty`: this determines what kind of algorithm micro uses to determine if
|
||||
a buffer is modified or not. When `fastdirty` is on, micro just uses a
|
||||
boolean `modified` that is set to `true` as soon as the user makes an edit.
|
||||
This is fast, but can be inaccurate. If `fastdirty` is off, then micro will
|
||||
hash the current buffer against a hash of the original file (created when the
|
||||
buffer was loaded). This is more accurate but obviously more resource
|
||||
intensive. This option is only for people who really care about having
|
||||
accurate modified status.
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `fileformat`: this determines what kind of line endings micro will use for the
|
||||
file. UNIX line endings are just `\n` (lf) whereas dos line endings are
|
||||
`\r\n` (crlf). The two possible values for this option are `unix` and `dos`.
|
||||
The fileformat will be automatically detected and displayed on the statusline
|
||||
but this option is useful if you would like to change the line endings or if
|
||||
you are starting a new file.
|
||||
|
||||
default value: `unix`
|
||||
|
||||
* `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
|
||||
|
||||
* `ignorecase`: perform case-insensitive searches.
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `indentchar`: sets the indentation character.
|
||||
|
||||
default value: ` `
|
||||
|
||||
* `infobar`: enables the line at the bottom of the editor where messages are
|
||||
printed. This option is `global only`.
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `keepautoindent`: when using autoindent, whitespace is added for you. This
|
||||
option determines if when you move to the next line without any insertions
|
||||
the whitespace that was added should be deleted. By default the autoindent
|
||||
whitespace is deleted if the line was left empty.
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `keymenu`: display the nano-style key menu at the bottom of the screen. Note
|
||||
that ToggleKeyMenu is bound to `Alt-g` by default and this is displayed in
|
||||
the statusline. To disable this, simply by `Alt-g` to `UnbindKey`.
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `mouse`: whether to enable mouse support. When mouse support is disabled,
|
||||
usually the terminal will be able to access mouse events which can be useful
|
||||
if you want to copy from the terminal instead of from micro (if over ssh for
|
||||
example, because the terminal has access to the local clipboard and micro
|
||||
does not).
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `pluginchannels`: contains all the channels micro's plugin manager will search
|
||||
for plugins in. A channel is simply a list of 'repository' json files which
|
||||
contain metadata about the given plugin. See the `Plugin Manager` section of
|
||||
the `plugins` help topic for more information.
|
||||
|
||||
default value: `https://github.com/micro-editor/plugin-channel`
|
||||
|
||||
* `pluginrepos`: contains all the 'repositories' micro's plugin manager will
|
||||
search for plugins in. A repository consists of a `repo.json` file which
|
||||
contains metadata for a single plugin.
|
||||
|
||||
default value: ` `
|
||||
|
||||
* `rmtrailingws`: micro will automatically trim trailing whitespaces at eol.
|
||||
|
||||
default value: `false`
|
||||
|
||||
* `ruler`: display line numbers.
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `savecursor`: remember where the cursor was last time the file was opened and
|
||||
put it there when you open the file again.
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `savehistory`: remember command history between closing and re-opening
|
||||
micro.
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `saveundo`: when this option is on, undo is saved even after you close a file
|
||||
so if you close and reopen a file, you can keep undoing.
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `scrollbar`: display a scroll bar
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `scrollmargin`: amount of lines you would like to see above and below the
|
||||
cursor.
|
||||
|
||||
default value: `3`
|
||||
|
||||
* `scrollspeed`: amount of lines to scroll for one scroll event.
|
||||
|
||||
default value: `2`
|
||||
|
||||
* `softwrap`: should micro wrap lines that are too long to fit on the screen.
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `splitbottom`: when a horizontal split is created, should it be created below
|
||||
the current split?
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `splitright`: when a vertical split is created, should it be created to the
|
||||
right of the current split?
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `statusline`: display the status line at the bottom of the screen.
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `syntax`: turns syntax on or off.
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `sucmd`: specifies the super user command. On most systems this is "sudo" but
|
||||
on BSD it can be "doas." This option can be customized and is only used when
|
||||
saving with su.
|
||||
|
||||
default value: `sudo`
|
||||
|
||||
* `tabmovement`: navigate spaces at the beginning of lines as if they are tabs
|
||||
(e.g. move over 4 spaces at once). This option only does anything if
|
||||
`tabstospaces` is on.
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `tabsize`: sets the tab size to `option`
|
||||
|
||||
default value: `4`
|
||||
|
||||
* `indentchar`: sets the indentation character
|
||||
|
||||
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
|
||||
|
||||
* `ignorecase`: perform case-insensitive searches
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `syntax`: turns syntax on or off
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `tabstospaces`: use spaces instead of tabs
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `tabmovement`: navigate spaces at the beginning of lines as if they are tabs (e.g. move over 4 spaces at once).
|
||||
This option only does anything if `tabstospaces` is on.
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `autoindent`: when creating a new line use the same indentation as the
|
||||
previous line
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `cursorline`: highlight the line that the cursor is on in a different color
|
||||
(the color is defined by the colorscheme you are using)
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `ruler`: display line numbers
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `statusline`: display the status line at the bottom of the screen
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `savecursor`: remember where the cursor was last time the file was opened and
|
||||
put it there when you open the file again
|
||||
* `termtitle`: defines whether or not your terminal's title will be set by micro
|
||||
when opened.
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `saveundo`: when this option is on, undo is saved even after you close a file
|
||||
so if you close and reopen a file, you can keep undoing
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `scrollmargin`: amount of lines you would like to see above and below the cursor
|
||||
|
||||
default value: `3`
|
||||
|
||||
* `scrollspeed`: amount of lines to scroll for one scroll event
|
||||
|
||||
default value: `2`
|
||||
|
||||
* `softwrap`: should micro wrap lines that are too long to fit on the screen
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `splitRight`: when a vertical split is created, should it be created to the right of
|
||||
the current split?
|
||||
* `useprimary` (only useful on *nix): defines whether or not micro will use the
|
||||
primary clipboard to copy selections in the background. This does not affect
|
||||
the normal clipboard using Ctrl-C and Ctrl-V.
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `splitBottom`: when a horizontal split is created, should it be created below the
|
||||
current split?
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `autosave`: micro will save the buffer every 8 seconds automatically.
|
||||
Micro also will automatically save and quit when you exit without asking.
|
||||
Be careful when using this feature, because you might accidentally save a file,
|
||||
overwriting what was there before.
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `pluginchannels`: contains all the channels micro's plugin manager will search
|
||||
for plugins in. A channel is simply a list of 'repository' json files which contain
|
||||
metadata about the given plugin. See the `Plugin Manager` section of the `plugins` help topic
|
||||
for more information.
|
||||
|
||||
default value: `https://github.com/micro-editor/plugin-channel`
|
||||
|
||||
* `pluginrepos`: contains all the 'repositories' micro's plugin manager will search for
|
||||
plugins in. A repository consists of a `repo.json` file which contains metadata for a
|
||||
single plugin.
|
||||
|
||||
default value: ` `
|
||||
|
||||
* `useprimary` (only useful on Linux): defines whether or not micro will use the primary clipboard to copy selections
|
||||
in the background. This does not affect the normal clipboard using Ctrl-C and Ctrl-V.
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `keepautoindent`: when using autoindent, whitespace is added for you. This option determines if
|
||||
when you move to the next line without any insertions the whitespace that was added should be deleted.
|
||||
By default the autoindent whitespace is deleted if the line was left empty.
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `termtitle`: defines whether or not your terminal's title will be set by micro when opened.
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `mouse`: whether to enable mouse support. When mouse support is disabled, usually the terminal will be able
|
||||
to access mouse events which can be useful if you want to copy from the terminal instead of from micro (if
|
||||
over ssh for example, because the terminal has access to the local clipboard and micro does not).
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `fileformat`: this determines what kind of line endings micro will use for the file. Unix line endings
|
||||
are just `\n` (lf) whereas dos line endings are `\r\n` (crlf). The two possible values for this option
|
||||
are `unix` and `dos`. The fileformat will be automatically detected and displayed on the statusline but
|
||||
this option is useful if you would like to change the line endings or if you are starting a new file.
|
||||
|
||||
default value: `unix`
|
||||
|
||||
* `fastdirty`: this determines what kind of algorithm micro uses to determine if a buffer is modified or
|
||||
not. When `fastdirty` is on, micro just uses a boolean `modified` that is set to `true` as soon as the user
|
||||
makes an edit. This is fast, but can be inaccurate. If `fastdirty` is off, then micro will hash the current
|
||||
buffer against a hash of the original file (created when the buffer was loaded). This is more accurate but
|
||||
obviously more resource intensive. This option is only for people who really care about having accurate
|
||||
modified status.
|
||||
|
||||
default value: `on`
|
||||
|
||||
---
|
||||
|
||||
Default plugin options:
|
||||
|
||||
* `autoclose`: Automatically close `{}` `()` `[]` `""` `''`. Provided by the `autoclose` plugin
|
||||
* `autoclose`: automatically close `{}` `()` `[]` `""` `''`. Provided by the
|
||||
`autoclose` plugin
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `linter`: Automatically lint when the file is saved. Provided by the `linter` plugin
|
||||
* `ftoptions`: by default, micro will set some options based on the filetype. At
|
||||
the moment, micro will use tabs for makefiles and spaces for python and yaml
|
||||
files regardless of your settings. If you would like to disable this behavior
|
||||
turn this option off.
|
||||
|
||||
default value: `on`
|
||||
|
||||
* `ftoptions`: by default, micro will set some options based on the filetype. At the moment, micro will
|
||||
use tabs for makefiles and spaces for python files regardless of your settings. If you would like to
|
||||
disable this behavior turn this option off.
|
||||
* `linter`: Automatically lint when the file is saved. Provided by the `linter`
|
||||
plugin.
|
||||
|
||||
default value: `on`
|
||||
|
||||
@@ -200,31 +238,33 @@ Any option you set in the editor will be saved to the file
|
||||
created for you. If you'd like to take your configuration with you to another
|
||||
machine, simply copy the settings.json to the other machine.
|
||||
|
||||
# Global and local settings
|
||||
|
||||
You can set these settings either globally or locally. Locally means that the setting
|
||||
won't be saved to `~/.config/micro/settings.json` and that it will only be set in
|
||||
the current buffer. Setting an option globally is the default, and will set the option
|
||||
in all buffers.
|
||||
## Global and local settings
|
||||
|
||||
The `colorscheme` option is global only, and the `filetype` option is local only. To
|
||||
set an option locally, use `setlocal` instead of `set`.
|
||||
You can set these settings either globally or locally. Locally means that the
|
||||
setting won't be saved to `~/.config/micro/settings.json` and that it will only
|
||||
be set in the current buffer. Setting an option globally is the default, and
|
||||
will set the option in all buffers.
|
||||
|
||||
In the `settings.json` file you can also put set options locally by specifying a glob.
|
||||
Here is an example which has `tabstospaces` on for all files except Go files, and
|
||||
`tabsize` 4 for all files except Ruby files:
|
||||
The `colorscheme` option is global only, and the `filetype` option is local
|
||||
only. To set an option locally, use `setlocal` instead of `set`.
|
||||
|
||||
In the `settings.json` file you can also put set options locally by specifying a
|
||||
glob. Here is an example which has `tabstospaces` on for all files except Go
|
||||
files, and `tabsize` 4 for all files except Ruby files:
|
||||
|
||||
```json
|
||||
{
|
||||
"*.go": {
|
||||
"tabstospaces": false
|
||||
},
|
||||
"*.rb": {
|
||||
"tabsize": 2
|
||||
},
|
||||
"tabstospaces": true,
|
||||
"tabsize": 4
|
||||
"*.go": {
|
||||
"tabstospaces": false
|
||||
},
|
||||
"*.rb": {
|
||||
"tabsize": 2
|
||||
},
|
||||
"tabstospaces": true,
|
||||
"tabsize": 4
|
||||
}
|
||||
```
|
||||
|
||||
As you can see it is quite easy to set options locally using the `settings.json` file.
|
||||
As you can see it is quite easy to set options locally using the `settings.json`
|
||||
file.
|
||||
|
||||
@@ -4,10 +4,9 @@ Micro supports creating plugins with a simple Lua system. Every plugin has a
|
||||
main script which is run at startup which should be placed in
|
||||
`~/.config/micro/plugins/pluginName/pluginName.lua`.
|
||||
|
||||
There are a number of callback functions which you can create in your
|
||||
plugin to run code at times other than startup. The naming scheme is
|
||||
`onAction(view)`. For example a function which is run every time the user saves
|
||||
the buffer would be:
|
||||
There are a number of callback functions which you can create in your plugin to
|
||||
run code at times other than startup. The naming scheme is `onAction(view)`. For
|
||||
example a function which is run every time the user saves the buffer would be:
|
||||
|
||||
```lua
|
||||
function onSave(view)
|
||||
@@ -17,7 +16,8 @@ end
|
||||
```
|
||||
|
||||
The `view` variable is a reference to the view the action is being executed on.
|
||||
This is almost always the current view, which you can get with `CurView()` as well.
|
||||
This is almost always the current view, which you can get with `CurView()` as
|
||||
well.
|
||||
|
||||
All available actions are listed in the keybindings section of the help.
|
||||
|
||||
@@ -31,27 +31,28 @@ function onMousePress(view, event)
|
||||
end
|
||||
```
|
||||
|
||||
These functions should also return a boolean specifying whether the view
|
||||
should be relocated to the cursor or not after the action is complete.
|
||||
These functions should also return a boolean specifying whether the view should
|
||||
be relocated to the cursor or not after the action is complete.
|
||||
|
||||
Note that these callbacks occur after the action has been completed. If you
|
||||
want a callback before the action is executed, use `preAction()`. In this case
|
||||
the boolean returned specifies whether or not the action should be executed
|
||||
after the lua code completes.
|
||||
Note that these callbacks occur after the action has been completed. If you want
|
||||
a callback before the action is executed, use `preAction()`. In this case the
|
||||
boolean returned specifies whether or not the action should be executed after
|
||||
the lua code completes.
|
||||
|
||||
Another useful callback to know about which is not a action is
|
||||
Another useful callback to know about which is not an action is
|
||||
`onViewOpen(view)` which is called whenever a new view is opened and the new
|
||||
view is passed in. This is useful for setting local options based on the filetype,
|
||||
for example turning off `tabstospaces` only for Go files when they are opened.
|
||||
view is passed in. This is useful for setting local options based on the
|
||||
filetype, 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
|
||||
order to access the inner workings of micro. Here is a list (the type signatures
|
||||
for functions are given using Go's type system):
|
||||
There are a number of functions and variables that are available to you in 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
|
||||
as Go's GOOS variable, so `darwin`, `windows`, `linux`, `freebsd`...)
|
||||
* `OS`: variable which gives the OS micro is currently running on (this is the
|
||||
same as Go's GOOS variable, so `darwin`, `windows`, `linux`, `freebsd`...)
|
||||
|
||||
* `configDir`: contains the path to the micro configuration files
|
||||
|
||||
@@ -61,29 +62,35 @@ as Go's GOOS variable, so `darwin`, `windows`, `linux`, `freebsd`...)
|
||||
|
||||
* `messenger`: lets you send messages to the user or create prompts
|
||||
|
||||
* `NewBuffer(text, path string) *Buffer`: creates a new buffer from a given reader with a given path
|
||||
* `NewBuffer(text, path string) *Buffer`: creates a new buffer from a given
|
||||
reader with a given path
|
||||
|
||||
* `GetLeadingWhitespace() bool`: returns the leading whitespace of the given string
|
||||
* `GetLeadingWhitespace() bool`: returns the leading whitespace of the given
|
||||
string
|
||||
|
||||
* `IsWordChar(str string) bool`: returns whether or not the string is a 'word character'
|
||||
* `IsWordChar(str string) bool`: returns whether or not the string is a 'word
|
||||
character'
|
||||
|
||||
* `RuneStr(r rune) string`: returns a string containing the given rune
|
||||
|
||||
* `Loc(x, y int) Loc`: returns a new `Loc` struct
|
||||
|
||||
* `WorkingDirectory() string`: returns a rooted path name to the current working directory
|
||||
* `WorkingDirectory() string`: returns a rooted path name to the current working
|
||||
directory
|
||||
|
||||
* `JoinPaths(dir... string) string`: combines multiple directories to a full path
|
||||
* `JoinPaths(dir... string) string`: combines multiple directories to a full
|
||||
path
|
||||
|
||||
* `DirectoryName(path string)`: returns all but the last element of path ,typically the path's directory
|
||||
* `DirectoryName(path string)`: returns all but the last element of path,
|
||||
typically the path's directory
|
||||
|
||||
* `GetOption(name string)`: returns the value of the requested option
|
||||
|
||||
* `AddOption(name string, value interface{})`: sets the given option with the given
|
||||
value (`interface{}` means any type in Go)
|
||||
* `AddOption(name string, value interface{})`: sets the given option with the
|
||||
given value (`interface{}` means any type in Go)
|
||||
|
||||
* `SetOption(option, value string)`: sets the given option to the value. This will
|
||||
set the option globally, unless it is a local only option.
|
||||
* `SetOption(option, value string)`: sets the given option to the value. This
|
||||
will set the option globally, unless it is a local only option.
|
||||
|
||||
* `SetLocalOption(option, value string, view *View)`: sets the given option to
|
||||
the value locally in the given buffer
|
||||
@@ -91,8 +98,8 @@ as Go's GOOS variable, so `darwin`, `windows`, `linux`, `freebsd`...)
|
||||
* `BindKey(key, action string)`: binds `key` to `action`
|
||||
|
||||
* `MakeCommand(name, function string, completions ...Completion)`:
|
||||
creates a command with `name` which will call `function` when executed.
|
||||
Use 0 for completions to get NoCompletion.
|
||||
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`
|
||||
@@ -101,42 +108,49 @@ as Go's GOOS variable, so `darwin`, `windows`, `linux`, `freebsd`...)
|
||||
|
||||
* `HandleCommand(cmd string)`: runs the given 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.
|
||||
* `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.
|
||||
|
||||
* `ToCharPos(loc Loc, buf *Buffer) int`: returns the character position of a given x, y location
|
||||
* `ToCharPos(loc Loc, buf *Buffer) int`: returns the character position of a
|
||||
given x, y location
|
||||
|
||||
* `Reload`: (Re)load everything
|
||||
|
||||
* `ByteOffset(loc Loc, buf *Buffer) int`: exactly like `ToCharPos` except it it counts bytes instead of runes
|
||||
* `ByteOffset(loc Loc, buf *Buffer) int`: exactly like `ToCharPos` except it it
|
||||
counts bytes instead of runes
|
||||
|
||||
* `JobSpawn(cmdName string, cmdArgs []string, onStdout, onStderr, onExit string, userargs ...string)`:
|
||||
Starts running the given process in the background. `onStdout` `onStderr` and `onExit`
|
||||
are callbacks to lua functions which will be called when the given actions happen
|
||||
to the background process.
|
||||
`userargs` are the arguments which will get passed to the callback functions
|
||||
Starts running the given process in the background. `onStdout` `onStderr` and
|
||||
`onExit` are callbacks to lua functions which will be called when the given
|
||||
actions happen to the background process. `userargs` are the arguments which
|
||||
will get passed to the callback functions
|
||||
|
||||
* `JobStart(cmd string, onStdout, onStderr, onExit string, userargs ...string)`:
|
||||
Starts running the given shell command in the background. Note that the command execute
|
||||
is first parsed by a shell when using this command. It is executed with `sh -c`.
|
||||
Starts running the given shell command in the background. Note that the
|
||||
command execute is first parsed by a shell when using this command. It is
|
||||
executed with `sh -c`.
|
||||
|
||||
* `JobSend(cmd *exec.Cmd, data string)`: send a string into the stdin of the job process
|
||||
* `JobSend(cmd *exec.Cmd, data string)`: send a string into the stdin of the job
|
||||
process
|
||||
|
||||
* `JobStop(cmd *exec.Cmd)`: kill a job
|
||||
|
||||
This may seem like a small list of available functions but some of the objects
|
||||
returned by the functions have many methods. `CurView()` returns a view object
|
||||
which has all the actions which you can call. For example `CurView():Save(false)`.
|
||||
You can see the full list of possible actions in the keybindings help topic.
|
||||
The boolean on all the actions indicates whether or not the lua callbacks should
|
||||
be run. I would recommend generally sticking to false when making a plugin to
|
||||
avoid recursive problems, for example if you call `CurView():Save(true)` in `onSave()`.
|
||||
Just use `CurView():Save(false)` so that it won't call `onSave()` again.
|
||||
which has all the actions which you can call. For example
|
||||
`CurView():Save(false)`. You can see the full list of possible actions in the
|
||||
keybindings help topic. The boolean on all the actions indicates whether or not
|
||||
the lua callbacks should be run. I would recommend generally sticking to false
|
||||
when making a plugin to avoid recursive problems, for example if you call
|
||||
`CurView():Save(true)` in `onSave()`. Just use `CurView():Save(false)` so that
|
||||
it won't call `onSave()` again.
|
||||
|
||||
Using the view object, you can also access the buffer associated with that view
|
||||
by using `CurView().Buf`, which lets you access the `FileType`, `Path`, `Name`...
|
||||
by using `CurView().Buf`, which lets you access the `FileType`, `Path`,
|
||||
`Name`...
|
||||
|
||||
The possible methods which you can call using the `messenger` variable are:
|
||||
|
||||
@@ -146,7 +160,8 @@ The possible methods which you can call using the `messenger` variable are:
|
||||
* `messenger.Prompt(prompt, historyType string, completionType Completion) (string, bool)`
|
||||
* `messenger.AddLog(msg ...interface{})`
|
||||
|
||||
## Note
|
||||
#### Note
|
||||
|
||||
Go function signatures use `.` and lua uses `:` so
|
||||
|
||||
```go
|
||||
@@ -160,26 +175,31 @@ messenger:Message()
|
||||
```
|
||||
|
||||
If you want a standard prompt, just use
|
||||
|
||||
```lua
|
||||
messenger:Prompt(prompt, "", 0)
|
||||
```
|
||||
|
||||
Debug or logging your plugin can be done with below lua example code.
|
||||
|
||||
```lua
|
||||
messenger:AddLog("Message goes here ",pluginVariableToPrintHere)
|
||||
```
|
||||
|
||||
In Micro to see your plugin logging output press `CtrlE` then type `log`
|
||||
A logging window will open and any logging sent from your plugin will be displayed here.
|
||||
In Micro to see your plugin logging output press `CtrlE` then type `log`, a
|
||||
logging window will open and any logging sent from your plugin will be displayed
|
||||
here.
|
||||
|
||||
# Accessing the Go standard library
|
||||
|
||||
It is possible for your lua code to access many of the functions in the Go standard library.
|
||||
## Accessing the Go standard library
|
||||
|
||||
It is possible for your lua code to access many of the functions in the Go
|
||||
standard library.
|
||||
|
||||
Simply import the package you'd like and then you can use it. For example:
|
||||
|
||||
```lua
|
||||
local ioutil = import("ioutil")
|
||||
local ioutil = import("io/ioutil")
|
||||
local fmt = import("fmt")
|
||||
|
||||
local data, err = ioutil.ReadFile("SomeFile.txt")
|
||||
@@ -196,26 +216,49 @@ else
|
||||
end
|
||||
```
|
||||
|
||||
For a full list of which packages and functions from the standard library
|
||||
you can access, look at `lua.go` in the source code (it shouldn't be
|
||||
too hard to look through).
|
||||
Here are the packages from the Go standard library that you can access.
|
||||
Nearly all functions from these packages are supported. For an exact
|
||||
list of which functions are supported you can look through `lua.go`
|
||||
(which should be easy to understand).
|
||||
|
||||
# Adding help files, syntax files, or colorschemes in your plugin
|
||||
```
|
||||
fmt
|
||||
io
|
||||
io/ioutil
|
||||
net
|
||||
math
|
||||
math/rand
|
||||
os
|
||||
runtime
|
||||
path
|
||||
filepath
|
||||
strings
|
||||
regexp
|
||||
errors
|
||||
time
|
||||
```
|
||||
|
||||
You can use the `AddRuntimeFile(name, type, path string)` function to add various kinds of
|
||||
files to your plugin. For example, if you'd like to add a help topic to your plugin
|
||||
called `test`, you would create a `test.md` file, and call the function:
|
||||
For documentation for each of these functions, you can simply look
|
||||
through the Go standard library documentation.
|
||||
|
||||
## Adding help files, syntax files, or colorschemes in your plugin
|
||||
|
||||
You can use the `AddRuntimeFile(name, type, path string)` function to add
|
||||
various kinds of files to your plugin. For example, if you'd like to add a help
|
||||
topic to your plugin called `test`, you would create a `test.md` file, and call
|
||||
the function:
|
||||
|
||||
```lua
|
||||
AddRuntimeFile("test", "help", "test.md")
|
||||
```
|
||||
|
||||
Use `AddRuntimeFilesFromDirectory(name, type, dir, pattern)` to add a number of files
|
||||
to the runtime.
|
||||
To read the content of a runtime file use `ReadRuntimeFile(fileType, name string)`
|
||||
or `ListRuntimeFiles(fileType string)` for all runtime files.
|
||||
Use `AddRuntimeFilesFromDirectory(name, type, dir, pattern)` to add a number of
|
||||
files to the runtime. To read the content of a runtime file use
|
||||
`ReadRuntimeFile(fileType, name string)` or `ListRuntimeFiles(fileType string)`
|
||||
for all runtime files.
|
||||
|
||||
# Autocomplete command arguments
|
||||
|
||||
## Autocomplete command arguments
|
||||
|
||||
See this example to learn how to use `MakeCompletion` and `MakeCommand`
|
||||
|
||||
@@ -245,27 +288,32 @@ end
|
||||
MakeCommand("foo", "example.foo", MakeCompletion("example.complete"))
|
||||
```
|
||||
|
||||
# Default plugins
|
||||
|
||||
## Default plugins
|
||||
|
||||
For examples of plugins, see the default `autoclose` and `linter` plugins
|
||||
(stored in the normal micro core repo under `runtime/plugins`) as well as
|
||||
any plugins that are stored in the official channel [here](https://github.com/micro-editor/plugin-channel).
|
||||
(stored in the normal micro core repo under `runtime/plugins`) as well as any
|
||||
plugins that are stored in the official channel
|
||||
[here](https://github.com/micro-editor/plugin-channel).
|
||||
|
||||
# Plugin Manager
|
||||
|
||||
Micro also has a built in plugin manager which you can invoke with the `> plugin ...` command.
|
||||
## Plugin Manager
|
||||
|
||||
Micro also has a built in plugin manager which you can invoke with the
|
||||
`> plugin ...` command.
|
||||
|
||||
For the valid commands you can use, see the `command` help topic.
|
||||
|
||||
The manager fetches plugins from the channels (which is simply a list of plugin metadata)
|
||||
which it knows about. By default, micro only knows about the official channel which is located
|
||||
at github.com/micro-editor/plugin-channel but you can add your own third-party channels using
|
||||
the `pluginchannels` option and you can directly link third-party plugins to allow installation
|
||||
through the plugin manager with the `pluginrepos` option.
|
||||
The manager fetches plugins from the channels (which is simply a list of plugin
|
||||
metadata) which it knows about. By default, micro only knows about the official
|
||||
channel which is located at github.com/micro-editor/plugin-channel but you can
|
||||
add your own third-party channels using the `pluginchannels` option and you can
|
||||
directly link third-party plugins to allow installation through the plugin
|
||||
manager with the `pluginrepos` option.
|
||||
|
||||
If you'd like to publish a plugin you've made as an official plugin, you should upload your
|
||||
plugin online (to Github preferably) and add a `repo.json` file. This file will contain the
|
||||
metadata for your plugin. Here is an example:
|
||||
If you'd like to publish a plugin you've made as an official plugin, you should
|
||||
upload your plugin online (to Github preferably) and add a `repo.json` file.
|
||||
This file will contain the metadata for your plugin. Here is an example:
|
||||
|
||||
```json
|
||||
[{
|
||||
@@ -284,7 +332,8 @@ metadata for your plugin. Here is an example:
|
||||
}]
|
||||
```
|
||||
|
||||
Then open a pull request at github.com/micro-editor/plugin-channel adding a link to the
|
||||
raw `repo.json` that is in your plugin repository.
|
||||
To make updating the plugin work, the first line of your plugins lua code should contain the version of the plugin. (Like this: `VERSION = "1.0.0"`)
|
||||
Please make sure to use [semver](http://semver.org/) for versioning.
|
||||
Then open a pull request at github.com/micro-editor/plugin-channel adding a link
|
||||
to the raw `repo.json` that is in your plugin repository. To make updating the
|
||||
plugin work, the first line of your plugins lua code should contain the version
|
||||
of the plugin. (Like this: `VERSION = "1.0.0"`) Please make sure to use
|
||||
[semver](http://semver.org/) for versioning.
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
# Tutorial
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
### Plugins
|
||||
|
||||
Micro has a plugin manager which can automatically download plugins for you.
|
||||
To see the plugins 'official' plugins, go to github.com/micro-editor/plugin-channel.
|
||||
Micro has a plugin manager which can automatically download plugins for you. To
|
||||
see the plugins 'official' plugins, go to github.com/micro-editor/plugin-channel.
|
||||
|
||||
For example, if you'd like to install the snippets plugin (listed in that repo),
|
||||
just press `CtrlE` to execute a command, and type `plugin install snippets`.
|
||||
@@ -20,23 +20,23 @@ topic.
|
||||
### Settings
|
||||
|
||||
In micro, your settings are stored in `~/.config/micro/settings.json`, a file
|
||||
that is created the first time you run micro. It is a json file which holds
|
||||
all the settings and their values. To change an option, you can either
|
||||
change the value in the `settings.json` file, or you can type it in directly
|
||||
while using micro.
|
||||
that is created the first time you run micro. It is a json file which holds all
|
||||
the settings and their values. To change an option, you can either change the
|
||||
value in the `settings.json` file, or you can type it in directly while using
|
||||
micro.
|
||||
|
||||
Simply press CtrlE to go to command mode, and type `set option value` (in the
|
||||
future, I will use `> set option value` to indicate pressing CtrlE). The
|
||||
change will take effect immediately and will also be saved to the `settings.json`
|
||||
file so that the setting will stick even after you close micro.
|
||||
future, I will use `> set option value` to indicate pressing CtrlE). The change
|
||||
will take effect immediately and will also be saved to the `settings.json` file
|
||||
so that the setting will stick even after you close micro.
|
||||
|
||||
You can also set options locally which means that the setting will only have
|
||||
the value you give it in the buffer you set it in. For example, if you have
|
||||
two splits open, and you type `> setlocal tabsize 2`, the tabsize will only
|
||||
be 2 in the current buffer. Also micro will not save this local change to the
|
||||
You can also set options locally which means that the setting will only have the
|
||||
value you give it in the buffer you set it in. For example, if you have two
|
||||
splits open, and you type `> setlocal tabsize 2`, the tabsize will only be 2 in
|
||||
the current buffer. Also micro will not save this local change to the
|
||||
`settings.json` file. However, you can still set options locally in the
|
||||
`settings.json` file. For example, if you want the `tabsize` to be 2 only
|
||||
in Ruby files, and 4 otherwise, you could put the following in `settings.json`:
|
||||
`settings.json` file. For example, if you want the `tabsize` to be 2 only in
|
||||
Ruby files, and 4 otherwise, you could put the following in `settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -54,8 +54,8 @@ If you would like to know more about all the available options, see the
|
||||
|
||||
### Keybindings
|
||||
|
||||
Keybindings work in much the same way as options. You configure them using
|
||||
the `~/.config/micro/bindings.json` file.
|
||||
Keybindings work in much the same way as options. You configure them using the
|
||||
`~/.config/micro/bindings.json` file.
|
||||
|
||||
For example if you would like to bind `CtrlR` to redo you could put the
|
||||
following in `bindings.json`:
|
||||
@@ -78,8 +78,8 @@ what actions are available, see the `keybindings` help topic (`> help keybinding
|
||||
### Configuration with Lua
|
||||
|
||||
If you need more power than the json files provide, you can use the `init.lua`
|
||||
file. Create it in `~/.config/micro`. This file is a lua file that is run
|
||||
when micro starts and is essentially a one-file plugin.
|
||||
file. Create it in `~/.config/micro`. This file is a lua file that is run when
|
||||
micro starts and is essentially a one-file plugin.
|
||||
|
||||
I'll show you how to use the `init.lua` file by giving an example of how to
|
||||
create a binding to `CtrlR` which will execute `go run` on the current file,
|
||||
@@ -98,8 +98,8 @@ end
|
||||
BindKey("CtrlR", "init.gorun")
|
||||
```
|
||||
|
||||
Alternatively, you could get rid of the `BindKey` line, and put this line in
|
||||
the `bindings.json` file:
|
||||
Alternatively, you could get rid of the `BindKey` line, and put this line in the
|
||||
`bindings.json` file:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -107,5 +107,5 @@ the `bindings.json` file:
|
||||
}
|
||||
```
|
||||
|
||||
For more information about plugins and the lua system that micro uses, see
|
||||
the `plugins` help topic (`> help plugins`).
|
||||
For more information about plugins and the lua system that micro uses, see the
|
||||
`plugins` help topic (`> help plugins`).
|
||||
|
||||
@@ -9,9 +9,15 @@ function onViewOpen(view)
|
||||
|
||||
local ft = view.Buf.Settings["filetype"]
|
||||
|
||||
if ft == "makefile" or ft == "go" then
|
||||
if ft == "go" or
|
||||
ft == "makefile" then
|
||||
SetOption("tabstospaces", "off")
|
||||
elseif ft == "python" or ft == "python2" or ft == "python3" then
|
||||
elseif ft == "fish" or
|
||||
ft == "python" or
|
||||
ft == "python2" or
|
||||
ft == "python3" or
|
||||
ft == "yaml" or
|
||||
ft == "nim" then
|
||||
SetOption("tabstospaces", "on")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,37 +16,40 @@ function runLinter()
|
||||
if OS == "windows" then
|
||||
devnull = "NUL"
|
||||
else
|
||||
devnull = "/dev/null"
|
||||
devnull = "/dev/null"
|
||||
end
|
||||
if ft == "go" then
|
||||
lint("gobuild", "go", {"build", "-o", devnull}, "%f:%l: %m")
|
||||
lint("golint", "golint", {file}, "%f:%l:%d+: %m")
|
||||
elseif ft == "lua" then
|
||||
lint("luacheck", "luacheck", {"--no-color", file}, "%f:%l:%d+: %m")
|
||||
elseif ft == "python" then
|
||||
lint("pyflakes", "pyflakes", {file}, "%f:%l:.-:? %m")
|
||||
lint("mypy", "mypy", {file}, "%f:%l: %m")
|
||||
lint("pylint", "pylint", {"--output-format=parseable", "--reports=no", file}, "%f:%l: %m")
|
||||
elseif ft == "c" then
|
||||
|
||||
if ft == "c" then
|
||||
lint("gcc", "gcc", {"-fsyntax-only", "-Wall", "-Wextra", file}, "%f:%l:%d+:.+: %m")
|
||||
elseif ft == "c++" then
|
||||
lint("gcc", "gcc", {"-fsyntax-only","-std=c++14", "-Wall", "-Wextra", file}, "%f:%l:%d+:.+: %m")
|
||||
elseif ft == "swift" and OS == "darwin" then
|
||||
lint("switfc", "xcrun", {"swiftc", file}, "%f:%l:%d+:.+: %m")
|
||||
elseif ft == "swift" and OS == "linux" then
|
||||
lint("switfc", "swiftc", {file}, "%f:%l:%d+:.+: %m")
|
||||
elseif ft == "Objective-C" then
|
||||
lint("clang", "xcrun", {"clang", "-fsyntax-only", "-Wall", "-Wextra", file}, "%f:%l:%d+:.+: %m")
|
||||
elseif ft == "c++" then
|
||||
lint("gcc", "gcc", {"-fsyntax-only","-std=c++14", "-Wall", "-Wextra", file}, "%f:%l:%d+:.+: %m")
|
||||
elseif ft == "d" then
|
||||
lint("dmd", "dmd", {"-color=off", "-o-", "-w", "-wi", "-c", file}, "%f%(%l%):.+: %m")
|
||||
elseif ft == "go" then
|
||||
lint("gobuild", "go", {"build", "-o", devnull}, "%f:%l: %m")
|
||||
lint("golint", "golint", {file}, "%f:%l:%d+: %m")
|
||||
elseif ft == "java" then
|
||||
lint("javac", "javac", {"-d", dir, file}, "%f:%l: error: %m")
|
||||
elseif ft == "javascript" then
|
||||
lint("jshint", "jshint", {file}, "%f: line %l,.+, %m")
|
||||
elseif ft == "nim" then
|
||||
lint("nim", "nim", {"check", "--listFullPaths", "--stdout", "--hints:off", file}, "%f.%l, %d+. %m")
|
||||
elseif string.match(ft, "literate") then
|
||||
lint("literate", "lit", {"-c", file}, "%f:%l:%m")
|
||||
elseif ft == "lua" then
|
||||
lint("luacheck", "luacheck", {"--no-color", file}, "%f:%l:%d+: %m")
|
||||
elseif ft == "nim" then
|
||||
lint("nim", "nim", {"check", "--listFullPaths", "--stdout", "--hints:off", file}, "%f.%l, %d+. %m")
|
||||
elseif ft == "Objective-C" then
|
||||
lint("clang", "xcrun", {"clang", "-fsyntax-only", "-Wall", "-Wextra", file}, "%f:%l:%d+:.+: %m")
|
||||
elseif ft == "python" then
|
||||
lint("pyflakes", "pyflakes", {file}, "%f:%l:.-:? %m")
|
||||
lint("mypy", "mypy", {file}, "%f:%l: %m")
|
||||
lint("pylint", "pylint", {"--output-format=parseable", "--reports=no", file}, "%f:%l: %m")
|
||||
elseif ft == "shell" then
|
||||
lint("shfmt", "shfmt", {file}, "%f:%l:%d+: %m")
|
||||
elseif ft == "swift" and OS == "darwin" then
|
||||
lint("switfc", "xcrun", {"swiftc", file}, "%f:%l:%d+:.+: %m")
|
||||
elseif ft == "swift" and OS == "linux" then
|
||||
lint("switfc", "swiftc", {file}, "%f:%l:%d+:.+: %m")
|
||||
elseif ft == "yaml" then
|
||||
lint("yaml", "yamllint", {"--format", "parsable", file}, "%f:%l:%d+:.+ %m")
|
||||
end
|
||||
|
||||
@@ -25,7 +25,7 @@ Most the the syntax files here have been converted using that tool.
|
||||
|
||||
Note that the tool isn't perfect and though it is unlikely, you may run into some small issues that you will have to fix manually
|
||||
(about 4 files from this directory had issues after being converted).
|
||||
=======
|
||||
|
||||
# Micro syntax highlighting files
|
||||
|
||||
These are the syntax highlighting files for micro. To install them, just
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
filetype: clojure
|
||||
|
||||
detect:
|
||||
filename: "\\.(clj)$"
|
||||
filename: "\\.(clj[sc]?)$"
|
||||
|
||||
rules:
|
||||
|
||||
|
||||
@@ -11,11 +11,9 @@ rules:
|
||||
- symbol.operator: "[-+/*=<>!~%&|^]|:="
|
||||
|
||||
# Types
|
||||
- special: "[a-zA-Z0-9]*\\("
|
||||
- symbol: "(,|\\.)"
|
||||
- type: "\\b(u?int(8|16|32|64)?|float(32|64)|complex(64|128))\\b"
|
||||
- type: "\\b(uintptr|byte|rune|string|interface|bool|map|chan|error)\\b"
|
||||
##I'm... not sure, but aren't structs a type?
|
||||
- type.keyword: "\\b(struct)\\b"
|
||||
- constant.bool: "\\b(true|false|nil)\\b"
|
||||
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
filetype: javascript
|
||||
|
||||
detect:
|
||||
filename: "\\.js$"
|
||||
filename: "(\\.js$|\\.es[5678]?$)"
|
||||
header: "^#!.*/(env +)?node( |$)"
|
||||
|
||||
rules:
|
||||
- constant.number: "\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\\b"
|
||||
- constant.number: "\\b[-+]?([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+)([EePp][+-]?[0-9]+)?[fFlL]?"
|
||||
- constant.number: "\\b[-+]?([0-9]+[EePp][+-]?[0-9]+)[fFlL]?"
|
||||
- identifier: "[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[(]"
|
||||
- symbol.brackets: "(\\{|\\})"
|
||||
- symbol.brackets: "(\\(|\\))"
|
||||
- symbol.brackets: "(\\[|\\])"
|
||||
- symbol.brackets: "(\\{|\\})"
|
||||
- symbol.brackets: "(\\(|\\))"
|
||||
- symbol.brackets: "(\\[|\\])"
|
||||
- statement: "\\b(break|case|catch|continue|default|delete|do|else|finally)\\b"
|
||||
- statement: "\\b(for|function|get|if|in|instanceof|new|return|set|switch)\\b"
|
||||
- statement: "\\b(switch|this|throw|try|typeof|var|void|while|with)\\b"
|
||||
- statement: "\\b(for|function|class|extends|get|if|in|instanceof|new|return|set|switch|async|await)\\b"
|
||||
- statement: "\\b(switch|this|throw|try|typeof|var|const|let|void|while|with)\\b"
|
||||
- constant: "\\b(null|undefined|NaN)\\b"
|
||||
- constant: "\\b(true|false)\\b"
|
||||
- type: "\\b(Array|Boolean|Date|Enumerator|Error|Function|Math)\\b"
|
||||
|
||||
@@ -22,7 +22,7 @@ rules:
|
||||
- constant: "\\b(false|nil|true)\\b"
|
||||
- statement: "(\\b(dofile|require|include)|%q|%!|%Q|%r|%x)\\b"
|
||||
- constant.number: "\\b([0-9]+)\\b"
|
||||
- symbol: "(\\(|\\)|\\[|\\]|\\{|\\}|\\*\\*|\\*|/|%|\\+|-|\\^|>|>=|<|<=|~=|=|\\.\\.)"
|
||||
- symbol: "(\\(|\\)|\\[|\\]|\\{|\\}|\\*\\*|\\*|/|%|\\+|-|\\^|>|>=|<|<=|~=|=|\\.\\.|#)"
|
||||
|
||||
- constant.string:
|
||||
start: "\""
|
||||
@@ -46,11 +46,6 @@ rules:
|
||||
|
||||
- special: "\\\\[0-7][0-7][0-7]|\\\\x[0-9a-fA-F][0-9a-fA-F]|\\\\[abefnrs]|(\\\\c|\\\\C-|\\\\M-|\\\\M-\\\\C-)."
|
||||
|
||||
- comment:
|
||||
start: "#"
|
||||
end: "$"
|
||||
rules: []
|
||||
|
||||
- comment:
|
||||
start: "\\-\\-"
|
||||
end: "$"
|
||||
|
||||
83
runtime/syntax/octave.yaml
Normal file
83
runtime/syntax/octave.yaml
Normal file
@@ -0,0 +1,83 @@
|
||||
# References
|
||||
# https://github.com/zyedidia/micro/blob/master/runtime/syntax/go.yaml
|
||||
# https://github.com/vim-scripts/octave.vim--/blob/master/syntax/octave.vim
|
||||
#
|
||||
# TODO
|
||||
# include only needed operators
|
||||
# ... highlighting
|
||||
# built-in function highlighting?
|
||||
# highlight eps/pi/e etc. as functions when followed by ()
|
||||
# what are skip and error fields in strings?
|
||||
# multiline comments not working
|
||||
|
||||
filetype: octave
|
||||
|
||||
detect:
|
||||
filename: "\\.m$"
|
||||
|
||||
rules:
|
||||
# Statements https://www.gnu.org/software/octave/doc/v4.0.0/Statements.html
|
||||
- statement: "\\b(function|endfunction|return|end|global|persistent)\\b"
|
||||
- statement: "\\b(if|elseif|else|endif|switch|case|otherwise|endswitch)\\b"
|
||||
- statement: "\\b(while|endwhile|do|until|for|endfor|parfor|endparfor|break|continue)\\b"
|
||||
- statement: "\\b(unwind_protect|unwind_protect_cleanup|end_unwind_protect|try|catch|end_try_catch)\\b"
|
||||
|
||||
# Operators
|
||||
- symbol.operator: "[-+/*=<>!~%&|^]|:="
|
||||
|
||||
# Brackets
|
||||
- symbol.brackets: "(\\{|\\})"
|
||||
- symbol.brackets: "(\\(|\\))"
|
||||
- symbol.brackets: "(\\[|\\])"
|
||||
|
||||
# Commas
|
||||
- symbol: ","
|
||||
|
||||
# Numbers https://www.gnu.org/software/octave/doc/v4.0.1/Mathematical-Constants.html
|
||||
- constant.number: "\\b([0-9]+|0x[0-9a-fA-F]*)\\b|'.'"
|
||||
- constant.number: "\\b(pi|e|I|Inf|NaN|eps|realmax|realmin)\\b|"
|
||||
|
||||
# Boolean
|
||||
- constant.bool: "\\b(true|false)\\b"
|
||||
|
||||
# Strings https://www.gnu.org/software/octave/doc/v4.0.1/Strings.html
|
||||
- constant.string:
|
||||
start: "\""
|
||||
end: "\""
|
||||
skip: "\\\\."
|
||||
rules:
|
||||
- constant.specialChar: "%"
|
||||
- constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]"
|
||||
- constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})"
|
||||
|
||||
- constant.string:
|
||||
start: "'"
|
||||
end: "'"
|
||||
skip: "\\\\."
|
||||
rules:
|
||||
- error: "..+"
|
||||
- constant.specialChar: "%"
|
||||
- constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]"
|
||||
- constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})"
|
||||
|
||||
# Comments https://www.gnu.org/software/octave/doc/v4.2.1/Comments.html
|
||||
- comment:
|
||||
start: "%"
|
||||
end: "$"
|
||||
rules:
|
||||
- todo: "(TODO|XXX|FIXME):?"
|
||||
- comment:
|
||||
start: "#"
|
||||
end: "$"
|
||||
rules:
|
||||
- todo: "(TODO|XXX|FIXME):?"
|
||||
- comment:
|
||||
start: "%{"
|
||||
end: "%}"
|
||||
rules:
|
||||
- todo: "(TODO|XXX|FIXME):?"
|
||||
- comment:
|
||||
start: "#{"
|
||||
end: "#}"
|
||||
rules:
|
||||
- todo: "(TODO|XXX|FIXME):?"
|
||||
@@ -6,7 +6,7 @@ detect:
|
||||
rules:
|
||||
- type: "\\b(boolean|byte|char|double|float|int|long|new|short|this|transient|void)\\b"
|
||||
- statement: "\\b(match|val|var|break|case|catch|continue|default|do|else|finally|for|if|return|switch|throw|try|while)\\b"
|
||||
- statement: "\\b(def|object|case|trait|lazy|implicit|abstract|class|extends|final|implements|import|instanceof|interface|native|package|private|protected|public|static|strictfp|super|synchronized|throws|volatile|sealed)\\b"
|
||||
- statement: "\\b(def|object|case|trait|lazy|implicit|abstract|class|extends|with|final|implements|override|import|instanceof|interface|native|package|private|protected|public|static|strictfp|super|synchronized|throws|volatile|sealed)\\b"
|
||||
- constant.string:
|
||||
start: "\""
|
||||
end: "\""
|
||||
|
||||
@@ -36,7 +36,7 @@ rules:
|
||||
rules: []
|
||||
|
||||
- comment:
|
||||
start: "#"
|
||||
start: "(^|[[:space:]])#"
|
||||
end: "$"
|
||||
rules:
|
||||
- todo: "(TODO|XXX|FIXME):?"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: micro
|
||||
version: master
|
||||
version: git
|
||||
summary: A modern and intuitive terminal-based text editor
|
||||
description: |
|
||||
Micro is a terminal-based text editor that aims to be easy to use and
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# Builds two .deb packages, for x86 (i386) and x86_64 (amd64)
|
||||
# These packages are the bare minimum, which means that they can be installed
|
||||
# But they do not feature everything yet.
|
||||
# This does not mean that the editor itself is affected.
|
||||
# Builds three .deb packages, for x86 (i386) and x86_64 (amd64) and arm (arm)
|
||||
# These packages include a manpage, an icon, and a desktop file.
|
||||
|
||||
function getControl() {
|
||||
echo Section: editors
|
||||
@@ -21,42 +19,56 @@ echo " and it supports mouse input"
|
||||
function installFiles() {
|
||||
TO="$1/$2/usr/share/doc/micro/"
|
||||
mkdir -p $TO
|
||||
mkdir -p "$1/$2/usr/share/man/man1/"
|
||||
mkdir -p "$1/$2/usr/share/applications/"
|
||||
mkdir -p "$1/$2/usr/share/icons/"
|
||||
cp ../LICENSE $TO
|
||||
cp ../LICENSE-THIRD-PARTY $TO
|
||||
cp ../README.md $TO
|
||||
gzip -c ../assets/packaging/micro.1 > $1/$2/usr/share/man/man1/micro.1.gz
|
||||
cp ../assets/packaging/micro.desktop $1/$2/usr/share/applications/
|
||||
cp ../assets/logo.svg $1/$2/usr/share/icons/micro.svg
|
||||
}
|
||||
|
||||
version=$1
|
||||
if [ "$1" == "" ]
|
||||
then
|
||||
version=$(go run build-version.go)
|
||||
then
|
||||
version=$(go run build-version.go | tr "-" ".")
|
||||
fi
|
||||
echo "Building packages for Version '$version'"
|
||||
echo "Running Cross-Compile"
|
||||
./cross-compile.sh $version
|
||||
|
||||
echo "Compiling."
|
||||
./compile-linux.sh $version
|
||||
|
||||
echo "Beginning package build process"
|
||||
|
||||
|
||||
PKGPATH="../packages/deb"
|
||||
|
||||
rm -fr ../packages
|
||||
|
||||
rm -fr $PKGPATH
|
||||
mkdir -p $PKGPATH/amd64/DEBIAN/
|
||||
mkdir -p $PKGPATH/i386/DEBIAN/
|
||||
mkdir -p $PKGPATH/arm/DEBIAN/
|
||||
|
||||
getControl "amd64" "$version" > $PKGPATH/amd64/DEBIAN/control
|
||||
tar -xzf "../binaries/micro-$version-linux64.tar.gz" "micro-$version/micro"
|
||||
mkdir -p $PKGPATH/amd64/usr/local/bin/
|
||||
mv "micro-$version/micro" "$PKGPATH/amd64/usr/local/bin/"
|
||||
|
||||
|
||||
getControl "i386" "$version" > $PKGPATH/i386/DEBIAN/control
|
||||
tar -xzf "../binaries/micro-$version-linux32.tar.gz" "micro-$version/micro"
|
||||
mkdir -p $PKGPATH/i386/usr/local/bin/
|
||||
mv "micro-$version/micro" "$PKGPATH/i386/usr/local/bin/"
|
||||
|
||||
|
||||
getControl "arm" "$version" > $PKGPATH/arm/DEBIAN/control
|
||||
tar -xzf "../binaries/micro-$version-linux-arm.tar.gz" "micro-$version/micro"
|
||||
mkdir -p $PKGPATH/arm/usr/local/bin
|
||||
mv "micro-$version/micro" "$PKGPATH/arm/usr/local/bin"
|
||||
|
||||
rm -rf "micro-$version"
|
||||
|
||||
|
||||
installFiles $PKGPATH "amd64"
|
||||
installFiles $PKGPATH "i386"
|
||||
|
||||
installFiles $PKGPATH "arm"
|
||||
|
||||
dpkg -b "$PKGPATH/amd64/" "../packages/micro-$version-amd64.deb"
|
||||
dpkg -b "$PKGPATH/i386/" "../packages/micro-$version-i386.deb"
|
||||
dpkg -b "$PKGPATH/arm/" "../packages/micro-$version-arm.deb"
|
||||
|
||||
129
tools/build-packages.sh
Executable file
129
tools/build-packages.sh
Executable file
@@ -0,0 +1,129 @@
|
||||
#Builds all packages we support
|
||||
|
||||
version=$1
|
||||
if [ "$1" == "" ]
|
||||
then
|
||||
version=$(go run build-version.go | tr "-" ".")
|
||||
fi
|
||||
echo "Building packages for Version '$version'"
|
||||
echo "Compiling."
|
||||
./compile-linux.sh $version
|
||||
|
||||
#Build the debs
|
||||
function getControl() {
|
||||
echo Section: editors
|
||||
echo Package: micro
|
||||
echo Version: $2
|
||||
echo Priority: extra
|
||||
echo Maintainer: \"Zachary Yedidia\" \<zyedidia@gmail.com\>
|
||||
echo Standards-Version: 3.9.8
|
||||
echo Homepage: https://micro-editor.github.io/
|
||||
echo Architecture: $1
|
||||
echo "Description: A modern and intuitive terminal-based text editor"
|
||||
echo " This package contains a modern alternative to other terminal-based"
|
||||
echo " Editors. It is easy to Use, highly customizable via themes and plugins"
|
||||
echo " and it supports mouse input"
|
||||
}
|
||||
|
||||
function installFiles() {
|
||||
TO="$1/$2/usr/share/doc/micro/"
|
||||
mkdir -p $TO
|
||||
mkdir -p "$1/$2/usr/share/man/man1/"
|
||||
mkdir -p "$1/$2/usr/share/applications/"
|
||||
mkdir -p "$1/$2/usr/share/icons/"
|
||||
cp ../LICENSE $TO
|
||||
cp ../LICENSE-THIRD-PARTY $TO
|
||||
cp ../README.md $TO
|
||||
gzip -c ../assets/packaging/micro.1 > $1/$2/usr/share/man/man1/micro.1.gz
|
||||
cp ../assets/packaging/micro.desktop $1/$2/usr/share/applications/
|
||||
cp ../assets/logo.svg $1/$2/usr/share/icons/micro.svg
|
||||
}
|
||||
echo "Starting deb build process"
|
||||
PKGPATH="../packages/deb"
|
||||
rm -fr $PKGPATH
|
||||
mkdir -p $PKGPATH/amd64/DEBIAN/
|
||||
mkdir -p $PKGPATH/i386/DEBIAN/
|
||||
mkdir -p $PKGPATH/arm/DEBIAN/
|
||||
|
||||
getControl "amd64" "$version" > $PKGPATH/amd64/DEBIAN/control
|
||||
tar -xzf "../binaries/micro-$version-linux64.tar.gz" "micro-$version/micro"
|
||||
mkdir -p $PKGPATH/amd64/usr/local/bin/
|
||||
mv "micro-$version/micro" "$PKGPATH/amd64/usr/local/bin/"
|
||||
|
||||
getControl "i386" "$version" > $PKGPATH/i386/DEBIAN/control
|
||||
tar -xzf "../binaries/micro-$version-linux32.tar.gz" "micro-$version/micro"
|
||||
mkdir -p $PKGPATH/i386/usr/local/bin/
|
||||
mv "micro-$version/micro" "$PKGPATH/i386/usr/local/bin/"
|
||||
|
||||
getControl "arm" "$version" > $PKGPATH/arm/DEBIAN/control
|
||||
tar -xzf "../binaries/micro-$version-linux-arm.tar.gz" "micro-$version/micro"
|
||||
mkdir -p $PKGPATH/arm/usr/local/bin
|
||||
mv "micro-$version/micro" "$PKGPATH/arm/usr/local/bin"
|
||||
|
||||
rm -rf "micro-$version"
|
||||
|
||||
installFiles $PKGPATH "amd64"
|
||||
installFiles $PKGPATH "i386"
|
||||
installFiles $PKGPATH "arm"
|
||||
|
||||
echo "Building debs"
|
||||
dpkg -b "$PKGPATH/amd64/" "../packages/micro-$version-amd64.deb"
|
||||
dpkg -b "$PKGPATH/i386/" "../packages/micro-$version-i386.deb"
|
||||
dpkg -b "$PKGPATH/arm/" "../packages/micro-$version-arm.deb"
|
||||
|
||||
#Build the RPMS
|
||||
echo "Starting RPM build process"
|
||||
PKGPATH="../packages/rpm"
|
||||
|
||||
rm -rf $PKGPATH
|
||||
mkdir -p $PKGPATH
|
||||
|
||||
versionsplit=$(echo $version | tr "." "\n")
|
||||
version=""
|
||||
i=0
|
||||
for string in $versionsplit
|
||||
do
|
||||
if (("$i" < "2"))
|
||||
then
|
||||
version=$(echo $version$string.)
|
||||
fi
|
||||
if (("$i" == "2"))
|
||||
then
|
||||
version=$(echo $version$string)
|
||||
fi
|
||||
if (("$i" == "3"))
|
||||
then
|
||||
dev=$(echo $dev$string.)
|
||||
fi
|
||||
if (("$i"=="4"))
|
||||
then
|
||||
dev=$(echo $dev$string)
|
||||
fi
|
||||
let "i+=1"
|
||||
done
|
||||
|
||||
#Generate the spec file from template
|
||||
cat micro.spec | sed s/"dev.126"/"$dev"/ | sed s/"Version: 1.1.5"/"Version: $version"/ | sed s/"-Version: 1.1.5"/"-Version: $version"/ | sed s/"DATE"/"$(date +%F\ %H:%m)"/ | sed s/"rdieter1@localhost.localdomain"/"$USER@$HOSTNAME"/ | tee > $PKGPATH/micro.spec
|
||||
|
||||
cd $PKGPATH
|
||||
|
||||
echo "Building the RPM packages"
|
||||
rpmbuild -bs micro.spec --define "_sourcedir $(pwd)/../../binaries/" --define "_rpmdir $(pwd)/../"
|
||||
rpmbuild -bb micro.spec --define "_sourcedir $(pwd)/../../binaries/" --define "_rpmdir $(pwd)/../" --target x86_64
|
||||
rpmbuild -bb micro.spec --define "_sourcedir $(pwd)/../../binaries/" --define "_rpmdir $(pwd)/../" --target i686
|
||||
rpmbuild -bb micro.spec --define "_sourcedir $(pwd)/../../binaries/" --define "_rpmdir $(pwd)/../" --target armv7l
|
||||
|
||||
cd ..
|
||||
|
||||
mv x86_64/micro-$version-1.$dev.x86_64.rpm ./
|
||||
mv i686/micro-$version-1.$dev.i686.rpm ./
|
||||
mv armv7l/micro-$version-1.$dev.armv7l.rpm ./
|
||||
|
||||
echo "Cleaning up."
|
||||
rm -rf x86_64
|
||||
rm -rf i686
|
||||
rm -rf armv7l
|
||||
rm -rf rpm
|
||||
rm -rf deb
|
||||
|
||||
echo "Your packages should be ready now. Thank you, have a nice day. :)"
|
||||
59
tools/build-rpm.sh
Executable file
59
tools/build-rpm.sh
Executable file
@@ -0,0 +1,59 @@
|
||||
#This script builds four rpm packages
|
||||
#One for x86 (i386) and x86_64 (amd64) and arm (armv7l)
|
||||
#and one containing the source tarball
|
||||
version=$1
|
||||
if [ "$1" == "" ]
|
||||
then
|
||||
version=$(go run build-version.go | tr "-" ".")
|
||||
fi
|
||||
echo "Building packages for Version '$version'"
|
||||
echo "Compiling."
|
||||
./compile-linux.sh $version
|
||||
|
||||
PKGPATH="../packages/rpm"
|
||||
|
||||
rm -rf $PKGPATH
|
||||
mkdir -p $PKGPATH
|
||||
versionsplit=$(echo $version | tr "." "\n")
|
||||
version=""
|
||||
i=0
|
||||
for string in $versionsplit
|
||||
do
|
||||
if (("$i" < "2"))
|
||||
then
|
||||
version=$(echo $version$string.)
|
||||
fi
|
||||
if (("$i" == "2"))
|
||||
then
|
||||
version=$(echo $version$string)
|
||||
fi
|
||||
if (("$i" == "3"))
|
||||
then
|
||||
dev=$(echo $dev$string.)
|
||||
fi
|
||||
if (("$i"=="4"))
|
||||
then
|
||||
dev=$(echo $dev$string)
|
||||
fi
|
||||
let "i+=1"
|
||||
done
|
||||
echo "Starting the packaging process"
|
||||
#Generate the spec file
|
||||
cat micro.spec | sed s/"dev.126"/"$dev"/ | sed s/"Version: 1.1.5"/"Version: $version"/ | sed s/"-Version: 1.1.5"/"-Version: $version"/ | sed s/"DATE"/"$(date +%F\ %H:%m)"/ | sed s/"rdieter1@localhost.localdomain"/"$USER@$HOSTNAME"/ | tee > $PKGPATH/micro.spec
|
||||
|
||||
cd $PKGPATH
|
||||
|
||||
rpmbuild -bs micro.spec --define "_sourcedir $(pwd)/../../binaries/" --define "_rpmdir $(pwd)/../"
|
||||
rpmbuild -bb micro.spec --define "_sourcedir $(pwd)/../../binaries/" --define "_rpmdir $(pwd)/../" --target x86_64
|
||||
rpmbuild -bb micro.spec --define "_sourcedir $(pwd)/../../binaries/" --define "_rpmdir $(pwd)/../" --target i686
|
||||
rpmbuild -bb micro.spec --define "_sourcedir $(pwd)/../../binaries/" --define "_rpmdir $(pwd)/../" --target armv7l
|
||||
|
||||
cd ..
|
||||
|
||||
mv x86_64/micro-$version-1.$dev.x86_64.rpm ./
|
||||
mv i686/micro-$version-1.$dev.i686.rpm ./
|
||||
mv armv7l/micro-$version-1.$dev.armv7l.rpm ./
|
||||
|
||||
rm -rf x86_64
|
||||
rm -rf i686
|
||||
rm -rf armv7l
|
||||
34
tools/compile-linux.sh
Executable file
34
tools/compile-linux.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
# Source tar
|
||||
|
||||
./vendor-src.sh micro-$1-src
|
||||
cd ..
|
||||
|
||||
mkdir -p binaries
|
||||
mkdir -p micro-$1
|
||||
|
||||
mv micro-$1-src.tar.gz binaries
|
||||
mv micro-$1-src.zip binaries
|
||||
|
||||
cp LICENSE micro-$1
|
||||
cp README.md micro-$1
|
||||
cp LICENSE-THIRD-PARTY micro-$1
|
||||
|
||||
HASH="$(git rev-parse --short HEAD)"
|
||||
VERSION="$(go run tools/build-version.go)"
|
||||
DATE="$(go run tools/build-date.go)"
|
||||
ADDITIONAL_GO_LINKER_FLAGS="$(go run tools/info-plist.go $VERSION)"
|
||||
|
||||
echo "Linux 64"
|
||||
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$DATE'" -o micro-$1/micro ./cmd/micro
|
||||
tar -czf micro-$1-linux64.tar.gz micro-$1
|
||||
mv micro-$1-linux64.tar.gz binaries
|
||||
echo "Linux 32"
|
||||
GOOS=linux GOARCH=386 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$DATE'" -o micro-$1/micro ./cmd/micro
|
||||
tar -czf micro-$1-linux32.tar.gz micro-$1
|
||||
mv micro-$1-linux32.tar.gz binaries
|
||||
echo "Linux arm"
|
||||
GOOS=linux GOARCH=arm go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$DATE'" -o micro-$1/micro ./cmd/micro
|
||||
tar -czf micro-$1-linux-arm.tar.gz micro-$1
|
||||
mv micro-$1-linux-arm.tar.gz binaries
|
||||
|
||||
rm -rf micro-$1
|
||||
71
tools/micro.spec
Normal file
71
tools/micro.spec
Normal file
@@ -0,0 +1,71 @@
|
||||
|
||||
%global dev_rev dev.126
|
||||
|
||||
Name: micro
|
||||
Version: 1.1.5
|
||||
Release: 1.%{dev_rev}
|
||||
Summary: A feature-rich terminal text editor
|
||||
URL: https://micro-editor.github.io
|
||||
Packager: Zachary Yedidia <zyedidia@gmail.com>
|
||||
License: MIT
|
||||
Group: Applications/Editors
|
||||
Source0: https://somethinghub.com/magicant/micro-binaries/micro-%{version}.%{dev_rev}-src.tar.gz
|
||||
|
||||
# disable debuginfo, using prebuilt binaries
|
||||
%global debug_package %{nil}
|
||||
|
||||
## x86_64 section
|
||||
Source1: https://somethinghub.com/magicant/micro-binaries/micro-%{version}.%{dev_rev}-linux64.tar.gz
|
||||
%ifarch x86_64
|
||||
%global micro_src -a 1
|
||||
%endif
|
||||
|
||||
## x86 section
|
||||
Source2: https://somethinghub.com/magicant/micro-binaries/micro-%{version}.%{dev_rev}-linux32.tar.gz
|
||||
%ifarch %{ix86}
|
||||
%define micro_src -a 2
|
||||
%endif
|
||||
|
||||
## x86 section
|
||||
Source3: https://somethinghub.com/magicant/micro-binaries/micro-%{version}.%{dev_rev}-linux-arm.tar.gz
|
||||
%ifarch %{arm}
|
||||
%define micro_src -a 3
|
||||
%endif
|
||||
|
||||
%description
|
||||
A modern and intuitive terminal-based text editor.
|
||||
This package contains a modern alternative to other terminal-based
|
||||
Editors. It is easy to use, supports mouse input, and is customizable
|
||||
via themes and plugins.
|
||||
|
||||
|
||||
%prep
|
||||
%setup -q -n %{name} %{?micro_src}
|
||||
|
||||
|
||||
%build
|
||||
# skipped, using pre-built binaries
|
||||
|
||||
|
||||
%install
|
||||
install -D -m 755 micro-%{version}.%{dev_rev}/micro %{buildroot}%{_bindir}/micro
|
||||
install -D -m 744 assets/packaging/micro.1 %{buildroot}%{_mandir}/man1/micro.1
|
||||
install -D -m 744 assets/packaging/micro.desktop %{buildroot}%{_datadir}/applications/micro.desktop
|
||||
install -D -m 744 assets/logo.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/apps/micro.svg
|
||||
|
||||
|
||||
%files
|
||||
%doc AUTHORS
|
||||
%doc LICENSE
|
||||
%doc LICENSE-THIRD-PARTY
|
||||
%doc README.md
|
||||
%{_bindir}/micro
|
||||
%{_mandir}/man1/micro.1*
|
||||
%{_datadir}/applications/micro.desktop
|
||||
%{_datadir}/icons/hicolor/scalable/apps/micro.svg
|
||||
|
||||
|
||||
%changelog
|
||||
* Thu Mar 30 2017 Zachary Yedidia <zyedidia@gmail.com>
|
||||
-Version: 1.1.5
|
||||
-Auto generated on DATE by rdieter1@localhost.localdomain
|
||||
Reference in New Issue
Block a user