mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-30 22:57:15 +09:00
Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c04a4ba604 | ||
|
|
63ccbc1ebd | ||
|
|
ee553b7830 | ||
|
|
97fc52093f | ||
|
|
49397039e0 | ||
|
|
efe1ab5db6 | ||
|
|
daeffdc81b | ||
|
|
30083c4d0f | ||
|
|
56e616d5bf | ||
|
|
112da0b8c6 | ||
|
|
163a3993bd | ||
|
|
1b9bb31dd6 | ||
|
|
8db3b22411 | ||
|
|
4aae5ca451 | ||
|
|
d3a3b7a8cd | ||
|
|
cc9342df9d | ||
|
|
fe0dce0960 | ||
|
|
766f836952 | ||
|
|
78b0aac5ec | ||
|
|
690627a338 | ||
|
|
25ced4c075 | ||
|
|
771b5333aa | ||
|
|
ae72608c5d | ||
|
|
2e778a2a8e | ||
|
|
bc9e811797 | ||
|
|
4db7f33eaf | ||
|
|
d3c5e3ab47 | ||
|
|
b13c6c4892 | ||
|
|
c50dda244b | ||
|
|
3fdc2ca0da | ||
|
|
6b7ca3c559 | ||
|
|
5c2a2b1b7e | ||
|
|
69e45f9a4f | ||
|
|
127ebc15b9 | ||
|
|
ea1de18326 | ||
|
|
edd25c68ee | ||
|
|
e30a4139e6 | ||
|
|
546acfd21d | ||
|
|
d27690b8c6 | ||
|
|
adc56e60fc | ||
|
|
266ce5c43b | ||
|
|
0bf07eadcc | ||
|
|
e4386d9398 | ||
|
|
c1dd403ab9 | ||
|
|
0e4f700527 | ||
|
|
a48c991958 | ||
|
|
cbc250b7d0 | ||
|
|
b27ef219a0 | ||
|
|
d163637fa8 | ||
|
|
905d4d7020 | ||
|
|
f85dd77036 | ||
|
|
8f5f8ffdd6 |
30
Makefile
30
Makefile
@@ -4,8 +4,10 @@ VERSION = $(shell go run tools/build-version.go)
|
||||
HASH = $(shell git rev-parse --short HEAD)
|
||||
DATE = $(shell go run tools/build-date.go)
|
||||
|
||||
GOBIN ?= $($GOPATH)/bin
|
||||
|
||||
# Builds micro after checking dependencies but without updating the runtime
|
||||
build: deps tcell
|
||||
build: deps
|
||||
go build -ldflags "-s -w -X main.Version=$(VERSION) -X main.CommitHash=$(HASH) -X 'main.CompileDate=$(DATE)'" ./cmd/micro
|
||||
|
||||
# Builds micro after building the runtime and checking dependencies
|
||||
@@ -15,31 +17,29 @@ build-all: runtime build
|
||||
build-quick:
|
||||
go build -ldflags "-s -w -X main.Version=$(VERSION) -X main.CommitHash=$(HASH) -X 'main.CompileDate=$(DATE)'" ./cmd/micro
|
||||
|
||||
# Same as 'build' but installs to $GOPATH/bin afterward
|
||||
install: build
|
||||
mkdir -p $(GOPATH)/bin
|
||||
mv micro $(GOPATH)/bin
|
||||
# Same as 'build' but installs to $GOBIN afterward
|
||||
install: deps
|
||||
go install -ldflags "-s -w -X main.Version=$(VERSION) -X main.CommitHash=$(HASH) -X 'main.CompileDate=$(DATE)'" ./cmd/micro
|
||||
|
||||
# Same as 'build-all' but installs to $GOPATH/bin afterward
|
||||
# Same as 'build-all' but installs to $GOBIN afterward
|
||||
install-all: runtime install
|
||||
|
||||
# Same as 'build-quick' but installs to $GOPATH/bin afterward
|
||||
install-quick: build-quick
|
||||
mkdir -p $(GOPATH)/bin
|
||||
mv micro $(GOPATH)/bin
|
||||
|
||||
# Updates tcell
|
||||
tcell:
|
||||
git -C $(GOPATH)/src/github.com/zyedidia/tcell pull
|
||||
# Same as 'build-quick' but installs to $GOBIN afterward
|
||||
install-quick:
|
||||
go install -ldflags "-s -w -X main.Version=$(VERSION) -X main.CommitHash=$(HASH) -X 'main.CompileDate=$(DATE)'" ./cmd/micro
|
||||
|
||||
# Checks for dependencies
|
||||
deps:
|
||||
go get -d ./cmd/micro
|
||||
|
||||
update:
|
||||
git pull
|
||||
go get -u -d ./cmd/micro
|
||||
|
||||
# Builds the runtime
|
||||
runtime:
|
||||
go get -u github.com/jteeuwen/go-bindata/...
|
||||
$(GOPATH)/bin/go-bindata -nometadata -o runtime.go runtime/...
|
||||
$(GOBIN)/go-bindata -nometadata -o runtime.go runtime/...
|
||||
mv runtime.go cmd/micro
|
||||
|
||||
test:
|
||||
|
||||
18
README.md
18
README.md
@@ -17,6 +17,8 @@ Here is a picture of micro editing its source code.
|
||||
|
||||
To see more screenshots of micro, showcasing all of the default colorschemes, see [here](http://zbyedidia.webfactional.com/micro/screenshots.html).
|
||||
|
||||
You can also check out the website for Micro at https://micro-editor.github.io.
|
||||
|
||||
# Features
|
||||
|
||||
* Easy to use and to install
|
||||
@@ -44,7 +46,7 @@ To see more screenshots of micro, showcasing all of the default colorschemes, se
|
||||
* Small and simple
|
||||
* Easily configurable
|
||||
* Macros
|
||||
* Common editor things such as undo/redo, line numbers, Unicode support...
|
||||
* Common editor things such as undo/redo, line numbers, Unicode support, softwrap...
|
||||
|
||||
Although not yet implemented, I hope to add more features such as autocompletion ([#174](https://github.com/zyedidia/micro/issues/174)), and multiple cursors ([#5](https://github.com/zyedidia/micro/issues/5)) in the future.
|
||||
|
||||
@@ -70,18 +72,24 @@ If you'd like to see more information after installing micro, run `micro -versio
|
||||
You can also install micro using Homebrew on Mac:
|
||||
|
||||
```
|
||||
$ brew install micro
|
||||
brew install 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).
|
||||
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).
|
||||
|
||||
```sh
|
||||
go get -u github.com/zyedidia/micro/...
|
||||
```
|
||||
go get -d github.com/zyedidia/micro
|
||||
cd $GOPATH/src/github.com/zyedidia/micro
|
||||
make install
|
||||
```
|
||||
|
||||
The binary will then be installed to `$GOPATH/bin` (or your `$GOBIN`).
|
||||
|
||||
You can install directly with `go get` (`go get -u github.com/zyedidia/micro/cmd/micro`) but this isn't recommended because it doesn't build micro with version information which is useful for the plugin manager.
|
||||
|
||||
### Linux clipboard support
|
||||
|
||||
|
||||
@@ -587,31 +587,17 @@ func (v *View) IndentSelection(usePlugin bool) bool {
|
||||
}
|
||||
|
||||
if v.Cursor.HasSelection() {
|
||||
start := v.Cursor.CurSelection[0].Y
|
||||
end := v.Cursor.CurSelection[1].Move(-1, v.Buf).Y
|
||||
startY := v.Cursor.CurSelection[0].Y
|
||||
endY := v.Cursor.CurSelection[1].Move(-1, v.Buf).Y
|
||||
endX := v.Cursor.CurSelection[1].Move(-1, v.Buf).X
|
||||
for i := start; i <= end; i++ {
|
||||
if v.Buf.Settings["tabstospaces"].(bool) {
|
||||
tabsize := int(v.Buf.Settings["tabsize"].(float64))
|
||||
v.Buf.Insert(Loc{0, i}, Spaces(tabsize))
|
||||
if i == start {
|
||||
if v.Cursor.CurSelection[0].X > 0 {
|
||||
v.Cursor.SetSelectionStart(v.Cursor.CurSelection[0].Move(tabsize, v.Buf))
|
||||
}
|
||||
}
|
||||
if i == end {
|
||||
v.Cursor.SetSelectionEnd(Loc{endX + tabsize + 1, end})
|
||||
}
|
||||
} else {
|
||||
v.Buf.Insert(Loc{0, i}, "\t")
|
||||
if i == start {
|
||||
if v.Cursor.CurSelection[0].X > 0 {
|
||||
v.Cursor.SetSelectionStart(v.Cursor.CurSelection[0].Move(1, v.Buf))
|
||||
}
|
||||
}
|
||||
if i == end {
|
||||
v.Cursor.SetSelectionEnd(Loc{endX + 2, end})
|
||||
}
|
||||
for y := startY; y <= endY; y++ {
|
||||
tabsize := len(v.Buf.IndentString())
|
||||
v.Buf.Insert(Loc{0, y}, v.Buf.IndentString())
|
||||
if y == startY && v.Cursor.CurSelection[0].X > 0 {
|
||||
v.Cursor.SetSelectionStart(v.Cursor.CurSelection[0].Move(tabsize, v.Buf))
|
||||
}
|
||||
if y == endY {
|
||||
v.Cursor.SetSelectionEnd(Loc{endX + tabsize + 1, endY})
|
||||
}
|
||||
}
|
||||
v.Cursor.Relocate()
|
||||
@@ -624,6 +610,31 @@ func (v *View) IndentSelection(usePlugin bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// OutdentLine moves the current line back one indentation
|
||||
func (v *View) OutdentLine(usePlugin bool) bool {
|
||||
if usePlugin && !PreActionCall("OutdentLine", v) {
|
||||
return false
|
||||
}
|
||||
|
||||
if v.Cursor.HasSelection() {
|
||||
return false
|
||||
}
|
||||
|
||||
for x := 0; x < len(v.Buf.IndentString()); x++ {
|
||||
if len(GetLeadingWhitespace(v.Buf.Line(v.Cursor.Y))) == 0 {
|
||||
break
|
||||
}
|
||||
v.Buf.Remove(Loc{0, v.Cursor.Y}, Loc{1, v.Cursor.Y})
|
||||
v.Cursor.X -= 1
|
||||
}
|
||||
v.Cursor.Relocate()
|
||||
|
||||
if usePlugin {
|
||||
return PostActionCall("OutdentLine", v)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// OutdentSelection takes the current selection and moves it back one indent level
|
||||
func (v *View) OutdentSelection(usePlugin bool) bool {
|
||||
if usePlugin && !PreActionCall("OutdentSelection", v) {
|
||||
@@ -631,37 +642,20 @@ func (v *View) OutdentSelection(usePlugin bool) bool {
|
||||
}
|
||||
|
||||
if v.Cursor.HasSelection() {
|
||||
start := v.Cursor.CurSelection[0].Y
|
||||
end := v.Cursor.CurSelection[1].Move(-1, v.Buf).Y
|
||||
startY := v.Cursor.CurSelection[0].Y
|
||||
endY := v.Cursor.CurSelection[1].Move(-1, v.Buf).Y
|
||||
endX := v.Cursor.CurSelection[1].Move(-1, v.Buf).X
|
||||
for i := start; i <= end; i++ {
|
||||
if len(GetLeadingWhitespace(v.Buf.Line(i))) > 0 {
|
||||
if v.Buf.Settings["tabstospaces"].(bool) {
|
||||
tabsize := int(v.Buf.Settings["tabsize"].(float64))
|
||||
for j := 0; j < tabsize; j++ {
|
||||
if len(GetLeadingWhitespace(v.Buf.Line(i))) == 0 {
|
||||
break
|
||||
}
|
||||
v.Buf.Remove(Loc{0, i}, Loc{1, i})
|
||||
if i == start {
|
||||
if v.Cursor.CurSelection[0].X > 0 {
|
||||
v.Cursor.SetSelectionStart(v.Cursor.CurSelection[0].Move(-1, v.Buf))
|
||||
}
|
||||
}
|
||||
if i == end {
|
||||
v.Cursor.SetSelectionEnd(Loc{endX - j, end})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
v.Buf.Remove(Loc{0, i}, Loc{1, i})
|
||||
if i == start {
|
||||
if v.Cursor.CurSelection[0].X > 0 {
|
||||
v.Cursor.SetSelectionStart(v.Cursor.CurSelection[0].Move(-1, v.Buf))
|
||||
}
|
||||
}
|
||||
if i == end {
|
||||
v.Cursor.SetSelectionEnd(Loc{endX, end})
|
||||
}
|
||||
for y := startY; y <= endY; y++ {
|
||||
for x := 0; x < len(v.Buf.IndentString()); x++ {
|
||||
if len(GetLeadingWhitespace(v.Buf.Line(y))) == 0 {
|
||||
break
|
||||
}
|
||||
v.Buf.Remove(Loc{0, y}, Loc{1, y})
|
||||
if y == startY && v.Cursor.CurSelection[0].X > 0 {
|
||||
v.Cursor.SetSelectionStart(v.Cursor.CurSelection[0].Move(-1, v.Buf))
|
||||
}
|
||||
if y == endY {
|
||||
v.Cursor.SetSelectionEnd(Loc{endX - x, endY})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -684,18 +678,11 @@ func (v *View) InsertTab(usePlugin bool) bool {
|
||||
if v.Cursor.HasSelection() {
|
||||
return false
|
||||
}
|
||||
// Insert a tab
|
||||
if v.Buf.Settings["tabstospaces"].(bool) {
|
||||
tabSize := int(v.Buf.Settings["tabsize"].(float64))
|
||||
if remainder := v.Cursor.Loc.X % tabSize; remainder != 0 {
|
||||
tabSize = tabSize - remainder
|
||||
}
|
||||
v.Buf.Insert(v.Cursor.Loc, Spaces(tabSize))
|
||||
for i := 0; i < tabSize; i++ {
|
||||
v.Cursor.Right()
|
||||
}
|
||||
} else {
|
||||
v.Buf.Insert(v.Cursor.Loc, "\t")
|
||||
|
||||
tabBytes := len(v.Buf.IndentString())
|
||||
bytesUntilIndent := tabBytes - (v.Cursor.GetVisualX() % tabBytes)
|
||||
v.Buf.Insert(v.Cursor.Loc, v.Buf.IndentString()[:bytesUntilIndent])
|
||||
for i := 0; i < bytesUntilIndent; i++ {
|
||||
v.Cursor.Right()
|
||||
}
|
||||
|
||||
@@ -775,12 +762,15 @@ func (v *View) Find(usePlugin bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
searchStr := ""
|
||||
if v.Cursor.HasSelection() {
|
||||
searchStart = ToCharPos(v.Cursor.CurSelection[1], v.Buf)
|
||||
searchStart = ToCharPos(v.Cursor.CurSelection[1], v.Buf)
|
||||
searchStr = v.Cursor.GetSelection()
|
||||
} else {
|
||||
searchStart = ToCharPos(v.Cursor.Loc, v.Buf)
|
||||
}
|
||||
BeginSearch()
|
||||
BeginSearch(searchStr)
|
||||
|
||||
if usePlugin {
|
||||
return PostActionCall("Find", v)
|
||||
@@ -796,9 +786,13 @@ func (v *View) FindNext(usePlugin bool) bool {
|
||||
|
||||
if v.Cursor.HasSelection() {
|
||||
searchStart = ToCharPos(v.Cursor.CurSelection[1], v.Buf)
|
||||
lastSearch = v.Cursor.GetSelection()
|
||||
} else {
|
||||
searchStart = ToCharPos(v.Cursor.Loc, v.Buf)
|
||||
}
|
||||
if lastSearch == "" {
|
||||
return true
|
||||
}
|
||||
messenger.Message("Finding: " + lastSearch)
|
||||
Search(lastSearch, v, true)
|
||||
|
||||
@@ -931,15 +925,20 @@ func (v *View) Cut(usePlugin bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// DuplicateLine duplicates the current line
|
||||
// DuplicateLine duplicates the current line or selection
|
||||
func (v *View) DuplicateLine(usePlugin bool) bool {
|
||||
if usePlugin && !PreActionCall("DuplicateLine", v) {
|
||||
return false
|
||||
}
|
||||
|
||||
v.Cursor.End()
|
||||
v.Buf.Insert(v.Cursor.Loc, "\n"+v.Buf.Line(v.Cursor.Y))
|
||||
v.Cursor.Right()
|
||||
if v.Cursor.HasSelection() {
|
||||
v.Buf.Insert(v.Cursor.CurSelection[1], v.Cursor.GetSelection())
|
||||
} else {
|
||||
v.Cursor.End()
|
||||
v.Buf.Insert(v.Cursor.Loc, "\n"+v.Buf.Line(v.Cursor.Y))
|
||||
v.Cursor.Right()
|
||||
}
|
||||
|
||||
messenger.Message("Duplicated line")
|
||||
|
||||
if usePlugin {
|
||||
@@ -968,6 +967,84 @@ func (v *View) DeleteLine(usePlugin bool) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// MoveLinesUp moves up the current line or selected lines if any
|
||||
func (v *View) MoveLinesUp(usePlugin bool) bool {
|
||||
if usePlugin && !PreActionCall("MoveLinesUp", v) {
|
||||
return false
|
||||
}
|
||||
|
||||
if v.Cursor.HasSelection() {
|
||||
if v.Cursor.CurSelection[0].Y == 0 {
|
||||
messenger.Message("Can not move further up")
|
||||
return true
|
||||
}
|
||||
v.Buf.MoveLinesUp(
|
||||
v.Cursor.CurSelection[0].Y,
|
||||
v.Cursor.CurSelection[1].Y,
|
||||
)
|
||||
v.Cursor.UpN(1)
|
||||
v.Cursor.CurSelection[0].Y -= 1
|
||||
v.Cursor.CurSelection[1].Y -= 1
|
||||
messenger.Message("Moved up selected line(s)")
|
||||
} else {
|
||||
if v.Cursor.Loc.Y == 0 {
|
||||
messenger.Message("Can not move further up")
|
||||
return true
|
||||
}
|
||||
v.Buf.MoveLinesUp(
|
||||
v.Cursor.Loc.Y,
|
||||
v.Cursor.Loc.Y+1,
|
||||
)
|
||||
v.Cursor.UpN(1)
|
||||
messenger.Message("Moved up current line")
|
||||
}
|
||||
v.Buf.IsModified = true
|
||||
|
||||
if usePlugin {
|
||||
return PostActionCall("MoveLinesUp", v)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// MoveLinesDown moves down the current line or selected lines if any
|
||||
func (v *View) MoveLinesDown(usePlugin bool) bool {
|
||||
if usePlugin && !PreActionCall("MoveLinesDown", v) {
|
||||
return false
|
||||
}
|
||||
|
||||
if v.Cursor.HasSelection() {
|
||||
if v.Cursor.CurSelection[1].Y >= len(v.Buf.lines) {
|
||||
messenger.Message("Can not move further down")
|
||||
return true
|
||||
}
|
||||
v.Buf.MoveLinesDown(
|
||||
v.Cursor.CurSelection[0].Y,
|
||||
v.Cursor.CurSelection[1].Y,
|
||||
)
|
||||
v.Cursor.DownN(1)
|
||||
v.Cursor.CurSelection[0].Y += 1
|
||||
v.Cursor.CurSelection[1].Y += 1
|
||||
messenger.Message("Moved down selected line(s)")
|
||||
} else {
|
||||
if v.Cursor.Loc.Y >= len(v.Buf.lines)-1 {
|
||||
messenger.Message("Can not move further down")
|
||||
return true
|
||||
}
|
||||
v.Buf.MoveLinesDown(
|
||||
v.Cursor.Loc.Y,
|
||||
v.Cursor.Loc.Y+1,
|
||||
)
|
||||
v.Cursor.DownN(1)
|
||||
messenger.Message("Moved down current line")
|
||||
}
|
||||
v.Buf.IsModified = true
|
||||
|
||||
if usePlugin {
|
||||
return PostActionCall("MoveLinesDown", v)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Paste whatever is in the system clipboard into the buffer
|
||||
// Delete and paste if the user has a selection
|
||||
func (v *View) Paste(usePlugin bool) bool {
|
||||
@@ -1305,6 +1382,21 @@ func (v *View) CommandMode(usePlugin bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Escape leaves current mode / quits the editor
|
||||
func (v *View) Escape(usePlugin bool) bool {
|
||||
// check if user is searching, or the last search is still active
|
||||
if searching || lastSearch != "" {
|
||||
ExitSearch(v)
|
||||
return true
|
||||
}
|
||||
// check if a prompt is shown, hide it and don't quit
|
||||
if messenger.hasPrompt {
|
||||
messenger.Reset() // FIXME
|
||||
return true
|
||||
}
|
||||
return v.Quit(usePlugin)
|
||||
}
|
||||
|
||||
// Quit quits the editor
|
||||
// This behavior needs to be changed and should really only quit the editor if this
|
||||
// is the last view
|
||||
@@ -1535,6 +1627,7 @@ func (v *View) PreviousSplit(usePlugin bool) bool {
|
||||
var curMacro []interface{}
|
||||
var recordingMacro bool
|
||||
|
||||
// ToggleMacro toggles recording of a macro
|
||||
func (v *View) ToggleMacro(usePlugin bool) bool {
|
||||
if usePlugin && !PreActionCall("ToggleMacro", v) {
|
||||
return false
|
||||
@@ -1555,6 +1648,7 @@ func (v *View) ToggleMacro(usePlugin bool) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// PlayMacro plays back the most recently recorded macro
|
||||
func (v *View) PlayMacro(usePlugin bool) bool {
|
||||
if usePlugin && !PreActionCall("PlayMacro", v) {
|
||||
return false
|
||||
|
||||
@@ -52,8 +52,11 @@ var bindingActions = map[string]func(*View, bool) bool{
|
||||
"CutLine": (*View).CutLine,
|
||||
"DuplicateLine": (*View).DuplicateLine,
|
||||
"DeleteLine": (*View).DeleteLine,
|
||||
"MoveLinesUp": (*View).MoveLinesUp,
|
||||
"MoveLinesDown": (*View).MoveLinesDown,
|
||||
"IndentSelection": (*View).IndentSelection,
|
||||
"OutdentSelection": (*View).OutdentSelection,
|
||||
"OutdentLine": (*View).OutdentLine,
|
||||
"Paste": (*View).Paste,
|
||||
"PastePrimary": (*View).PastePrimary,
|
||||
"SelectAll": (*View).SelectAll,
|
||||
@@ -72,6 +75,7 @@ var bindingActions = map[string]func(*View, bool) bool{
|
||||
"ClearStatus": (*View).ClearStatus,
|
||||
"ShellMode": (*View).ShellMode,
|
||||
"CommandMode": (*View).CommandMode,
|
||||
"Escape": (*View).Escape,
|
||||
"Quit": (*View).Quit,
|
||||
"QuitAll": (*View).QuitAll,
|
||||
"AddTab": (*View).AddTab,
|
||||
@@ -364,6 +368,8 @@ func DefaultBindings() map[string]string {
|
||||
"ShiftRight": "SelectRight",
|
||||
"AltLeft": "WordLeft",
|
||||
"AltRight": "WordRight",
|
||||
"AltUp": "MoveLinesUp",
|
||||
"AltDown": "MoveLinesDown",
|
||||
"AltShiftRight": "SelectWordRight",
|
||||
"AltShiftLeft": "SelectWordLeft",
|
||||
"CtrlLeft": "StartOfLine",
|
||||
@@ -381,7 +387,7 @@ func DefaultBindings() map[string]string {
|
||||
"Alt-CtrlH": "DeleteWordLeft",
|
||||
"Alt-Backspace": "DeleteWordLeft",
|
||||
"Tab": "IndentSelection,InsertTab",
|
||||
"Backtab": "OutdentSelection",
|
||||
"Backtab": "OutdentSelection,OutdentLine",
|
||||
"CtrlO": "OpenFile",
|
||||
"CtrlS": "Save",
|
||||
"CtrlF": "Find",
|
||||
@@ -429,6 +435,6 @@ func DefaultBindings() map[string]string {
|
||||
"F4": "Quit",
|
||||
"F7": "Find",
|
||||
"F10": "Quit",
|
||||
"Esc": "Quit",
|
||||
"Esc": "Escape",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +182,14 @@ func (b *Buffer) FileType() string {
|
||||
return b.Settings["filetype"].(string)
|
||||
}
|
||||
|
||||
// IndentString returns a string representing one level of indentation
|
||||
func (b *Buffer) IndentString() string {
|
||||
if b.Settings["tabstospaces"].(bool) {
|
||||
return Spaces(int(b.Settings["tabsize"].(float64)))
|
||||
}
|
||||
return "\t"
|
||||
}
|
||||
|
||||
// CheckModTime makes sure that the file this buffer points to hasn't been updated
|
||||
// by an external program since it was last read
|
||||
// If it has, we ask the user if they would like to reload the file
|
||||
@@ -261,7 +269,14 @@ func (b *Buffer) SaveAs(filename string) error {
|
||||
b.UpdateRules()
|
||||
b.Name = filename
|
||||
b.Path = filename
|
||||
data := []byte(b.String())
|
||||
str := b.String()
|
||||
if b.Settings["eofnewline"].(bool) {
|
||||
end := b.End()
|
||||
if b.RuneAt(Loc{end.X - 1, end.Y}) != '\n' {
|
||||
b.Insert(end, "\n")
|
||||
}
|
||||
}
|
||||
data := []byte(str)
|
||||
err := ioutil.WriteFile(filename, data, 0644)
|
||||
if err == nil {
|
||||
b.IsModified = false
|
||||
@@ -344,8 +359,20 @@ func (b *Buffer) End() Loc {
|
||||
return Loc{utf8.RuneCount(b.lines[b.NumLines-1]), b.NumLines - 1}
|
||||
}
|
||||
|
||||
// RuneAt returns the rune at a given location in the buffer
|
||||
func (b *Buffer) RuneAt(loc Loc) rune {
|
||||
line := []rune(b.Line(loc.Y))
|
||||
if len(line) > 0 {
|
||||
return line[loc.X]
|
||||
}
|
||||
return '\n'
|
||||
}
|
||||
|
||||
// Line returns a single line
|
||||
func (b *Buffer) Line(n int) string {
|
||||
if n >= len(b.lines) {
|
||||
return ""
|
||||
}
|
||||
return string(b.lines[n])
|
||||
}
|
||||
|
||||
@@ -363,3 +390,48 @@ func (b *Buffer) Lines(start, end int) []string {
|
||||
func (b *Buffer) Len() int {
|
||||
return Count(b.String())
|
||||
}
|
||||
|
||||
// MoveLinesUp moves the range of lines up one row
|
||||
func (b *Buffer) MoveLinesUp(start int, end int) {
|
||||
// 0 < start < end <= len(b.lines)
|
||||
if start < 1 || start >= end || end > len(b.lines) {
|
||||
return // what to do? FIXME
|
||||
}
|
||||
if end == len(b.lines) {
|
||||
b.Insert(
|
||||
Loc{
|
||||
utf8.RuneCount(b.lines[end-1]),
|
||||
end - 1,
|
||||
},
|
||||
"\n"+b.Line(start-1),
|
||||
)
|
||||
} else {
|
||||
b.Insert(
|
||||
Loc{0, end},
|
||||
b.Line(start-1)+"\n",
|
||||
)
|
||||
}
|
||||
b.Remove(
|
||||
Loc{0, start - 1},
|
||||
Loc{0, start},
|
||||
)
|
||||
}
|
||||
|
||||
// MoveLinesDown moves the range of lines down one row
|
||||
func (b *Buffer) MoveLinesDown(start int, end int) {
|
||||
// 0 <= start < end < len(b.lines)
|
||||
// if end == len(b.lines), we can't do anything here because the
|
||||
// last line is unaccessible, FIXME
|
||||
if start < 0 || start >= end || end >= len(b.lines)-1 {
|
||||
return // what to do? FIXME
|
||||
}
|
||||
b.Insert(
|
||||
Loc{0, start},
|
||||
b.Line(end)+"\n",
|
||||
)
|
||||
end++
|
||||
b.Remove(
|
||||
Loc{0, end},
|
||||
Loc{0, end + 1},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -26,22 +26,27 @@ type StrCommand struct {
|
||||
|
||||
var commands map[string]Command
|
||||
|
||||
var commandActions = map[string]func([]string){
|
||||
"Set": Set,
|
||||
"SetLocal": SetLocal,
|
||||
"Show": Show,
|
||||
"Run": Run,
|
||||
"Bind": Bind,
|
||||
"Quit": Quit,
|
||||
"Save": Save,
|
||||
"Replace": Replace,
|
||||
"VSplit": VSplit,
|
||||
"HSplit": HSplit,
|
||||
"Tab": NewTab,
|
||||
"Help": Help,
|
||||
"Eval": Eval,
|
||||
"ToggleLog": ToggleLog,
|
||||
"Plugin": PluginCmd,
|
||||
var commandActions map[string]func([]string)
|
||||
|
||||
func init() {
|
||||
commandActions = map[string]func([]string){
|
||||
"Set": Set,
|
||||
"SetLocal": SetLocal,
|
||||
"Show": Show,
|
||||
"Run": Run,
|
||||
"Bind": Bind,
|
||||
"Quit": Quit,
|
||||
"Save": Save,
|
||||
"Replace": Replace,
|
||||
"VSplit": VSplit,
|
||||
"HSplit": HSplit,
|
||||
"Tab": NewTab,
|
||||
"Help": Help,
|
||||
"Eval": Eval,
|
||||
"ToggleLog": ToggleLog,
|
||||
"Plugin": PluginCmd,
|
||||
"Reload": Reload,
|
||||
}
|
||||
}
|
||||
|
||||
// InitCommands initializes the default commands
|
||||
@@ -89,6 +94,7 @@ func DefaultCommands() map[string]StrCommand {
|
||||
"eval": {"Eval", []Completion{NoCompletion}},
|
||||
"log": {"ToggleLog", []Completion{NoCompletion}},
|
||||
"plugin": {"Plugin", []Completion{PluginCmdCompletion, PluginNameCompletion}},
|
||||
"reload": {"Reload", []Completion{NoCompletion}},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +184,10 @@ func ToggleLog(args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
func Reload(args []string) {
|
||||
LoadAll()
|
||||
}
|
||||
|
||||
// Help tries to open the given help page in a horizontal split
|
||||
func Help(args []string) {
|
||||
if len(args) < 1 {
|
||||
@@ -367,7 +377,7 @@ func Replace(args []string) {
|
||||
search := string(args[0])
|
||||
replace := string(args[1])
|
||||
|
||||
regex, err := regexp.Compile(search)
|
||||
regex, err := regexp.Compile("(?m)" + search)
|
||||
if err != nil {
|
||||
// There was an error with the user's regex
|
||||
messenger.Error(err.Error())
|
||||
@@ -414,23 +424,25 @@ func Replace(args []string) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
matches := regex.FindAllStringIndex(view.Buf.String(), -1)
|
||||
bufStr := view.Buf.String()
|
||||
matches := regex.FindAllStringIndex(bufStr, -1)
|
||||
if matches != nil && len(matches) > 0 {
|
||||
adjust := 0
|
||||
prevMatch := matches[0]
|
||||
from := FromCharPos(prevMatch[0], view.Buf)
|
||||
to := from.Move(Count(search), view.Buf)
|
||||
adjust += Count(replace) - Count(search)
|
||||
prevMatchCount := runePos(matches[0][0], bufStr)
|
||||
searchCount := runePos(matches[0][1], bufStr) - prevMatchCount
|
||||
from := FromCharPos(matches[0][0], view.Buf)
|
||||
to := from.Move(searchCount, view.Buf)
|
||||
adjust := Count(replace) - searchCount
|
||||
view.Buf.Replace(from, to, replace)
|
||||
if len(matches) > 1 {
|
||||
for _, match := range matches[1:] {
|
||||
found++
|
||||
from = from.Move(match[0]-prevMatch[0]+adjust, view.Buf)
|
||||
to := from.Move(Count(search), view.Buf)
|
||||
// TermMessage(match[0], " ", prevMatch[0], " ", adjust, "\n", from, " ", to)
|
||||
matchCount := runePos(match[0], bufStr)
|
||||
searchCount = runePos(match[1], bufStr) - matchCount
|
||||
from = from.Move(matchCount-prevMatchCount+adjust, view.Buf)
|
||||
to = from.Move(searchCount, view.Buf)
|
||||
view.Buf.Replace(from, to, replace)
|
||||
prevMatch = match
|
||||
// adjust += Count(replace) - Count(search)
|
||||
prevMatchCount = matchCount
|
||||
adjust = Count(replace) - searchCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +199,31 @@ func RedrawAll() {
|
||||
screen.Show()
|
||||
}
|
||||
|
||||
func LoadAll() {
|
||||
// Find the user's configuration directory (probably $XDG_CONFIG_HOME/micro)
|
||||
InitConfigDir()
|
||||
|
||||
// Build a list of available Extensions (Syntax, Colorscheme etc.)
|
||||
InitRuntimeFiles()
|
||||
|
||||
// Load the user's settings
|
||||
InitGlobalSettings()
|
||||
|
||||
InitCommands()
|
||||
InitBindings()
|
||||
|
||||
LoadSyntaxFiles()
|
||||
|
||||
for _, tab := range tabs {
|
||||
for _, v := range tab.views {
|
||||
v.Buf.UpdateRules()
|
||||
if v.Buf.Settings["syntax"].(bool) {
|
||||
v.matches = Match(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Passing -version as a flag will have micro print out the version number
|
||||
var flagVersion = flag.Bool("version", false, "Show the version number and information")
|
||||
var flagStartPos = flag.String("startpos", "", "LINE,COL to start the cursor at when opening a buffer.")
|
||||
@@ -206,7 +231,7 @@ var flagStartPos = flag.String("startpos", "", "LINE,COL to start the cursor at
|
||||
func main() {
|
||||
flag.Usage = func() {
|
||||
fmt.Println("Usage: micro [OPTIONS] [FILE]...")
|
||||
fmt.Println("Micro's options can be set via command line arguments for quick adjustments. For real configuration, please use the bindings.json file (see 'help options').\n")
|
||||
fmt.Print("Micro's options can be set via command line arguments for quick adjustments. For real configuration, please use the bindings.json file (see 'help options').\n\n")
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
@@ -234,17 +259,7 @@ func main() {
|
||||
encoding.Register()
|
||||
tcell.SetEncodingFallback(tcell.EncodingFallbackASCII)
|
||||
|
||||
// Find the user's configuration directory (probably $XDG_CONFIG_HOME/micro)
|
||||
InitConfigDir()
|
||||
|
||||
// Build a list of available Extensions (Syntax, Colorscheme etc.)
|
||||
InitRuntimeFiles()
|
||||
|
||||
// Load the user's settings
|
||||
InitGlobalSettings()
|
||||
|
||||
InitCommands()
|
||||
InitBindings()
|
||||
LoadAll()
|
||||
|
||||
// Start the screen
|
||||
InitScreen()
|
||||
@@ -319,6 +334,7 @@ func main() {
|
||||
}))
|
||||
L.SetGlobal("JoinPaths", luar.New(L, filepath.Join))
|
||||
L.SetGlobal("configDir", luar.New(L, configDir))
|
||||
L.SetGlobal("Reload", luar.New(L, LoadAll))
|
||||
|
||||
// Used for asynchronous jobs
|
||||
L.SetGlobal("JobStart", luar.New(L, JobStart))
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
allPluginPackages PluginPackages = nil
|
||||
allPluginPackages PluginPackages
|
||||
)
|
||||
|
||||
// CorePluginName is a plugin dependency name for the micro core.
|
||||
@@ -57,7 +57,7 @@ type PluginVersion struct {
|
||||
// PluginVersions is a slice of PluginVersion
|
||||
type PluginVersions []*PluginVersion
|
||||
|
||||
// PluginDenendency descripes a dependency to another plugin or micro itself.
|
||||
// PluginDependency descripes a dependency to another plugin or micro itself.
|
||||
type PluginDependency struct {
|
||||
Name string
|
||||
Range semver.Range
|
||||
@@ -246,9 +246,8 @@ func GetAllPluginPackages() PluginPackages {
|
||||
allPluginPackages = fetchAllSources(len(repos)+1, func(i int) PluginPackages {
|
||||
if i == 0 {
|
||||
return channels.Fetch()
|
||||
} else {
|
||||
return repos[i-1].Fetch()
|
||||
}
|
||||
return repos[i-1].Fetch()
|
||||
})
|
||||
}
|
||||
return allPluginPackages
|
||||
@@ -274,8 +273,8 @@ func (pv PluginVersions) Swap(i, j int) {
|
||||
}
|
||||
|
||||
// Less returns true if the version at position i is greater then the version at position j (used for sorting)
|
||||
func (s PluginVersions) Less(i, j int) bool {
|
||||
return s[i].Version.GT(s[j].Version)
|
||||
func (pv PluginVersions) Less(i, j int) bool {
|
||||
return pv[i].Version.GT(pv[j].Version)
|
||||
}
|
||||
|
||||
// Match returns true if the package matches a given search text
|
||||
@@ -382,6 +381,7 @@ func GetInstalledPluginVersion(name string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// DownloadAndInstall downloads and installs the given plugin and version
|
||||
func (pv *PluginVersion) DownloadAndInstall() error {
|
||||
messenger.AddLog(fmt.Sprintf("Downloading %q (%s) from %q", pv.pack.Name, pv.Version, pv.Url))
|
||||
resp, err := http.Get(pv.Url)
|
||||
@@ -439,13 +439,13 @@ func (pv *PluginVersion) DownloadAndInstall() error {
|
||||
return err
|
||||
}
|
||||
defer content.Close()
|
||||
if target, err := os.Create(targetName); err != nil {
|
||||
target, err := os.Create(targetName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer target.Close()
|
||||
if _, err = io.Copy(target, content); err != nil {
|
||||
return err
|
||||
} else {
|
||||
defer target.Close()
|
||||
if _, err = io.Copy(target, content); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -495,6 +495,7 @@ func (req PluginDependencies) Join(other PluginDependencies) PluginDependencies
|
||||
return result
|
||||
}
|
||||
|
||||
// Resolve resolves dependencies between different plugins
|
||||
func (all PluginPackages) Resolve(selectedVersions PluginVersions, open PluginDependencies) (PluginVersions, error) {
|
||||
if len(open) == 0 {
|
||||
return selectedVersions, nil
|
||||
@@ -506,31 +507,29 @@ func (all PluginPackages) Resolve(selectedVersions PluginVersions, open PluginDe
|
||||
return all.Resolve(selectedVersions, stillOpen)
|
||||
}
|
||||
return nil, fmt.Errorf("unable to find a matching version for \"%s\"", currentRequirement.Name)
|
||||
} else {
|
||||
availableVersions := all.GetAllVersions(currentRequirement.Name)
|
||||
sort.Sort(availableVersions)
|
||||
}
|
||||
availableVersions := all.GetAllVersions(currentRequirement.Name)
|
||||
sort.Sort(availableVersions)
|
||||
|
||||
for _, version := range availableVersions {
|
||||
if currentRequirement.Range(version.Version) {
|
||||
resolved, err := all.Resolve(append(selectedVersions, version), stillOpen.Join(version.Require))
|
||||
for _, version := range availableVersions {
|
||||
if currentRequirement.Range(version.Version) {
|
||||
resolved, err := all.Resolve(append(selectedVersions, version), stillOpen.Join(version.Require))
|
||||
|
||||
if err == nil {
|
||||
return resolved, nil
|
||||
}
|
||||
if err == nil {
|
||||
return resolved, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("unable to find a matching version for \"%s\"", currentRequirement.Name)
|
||||
}
|
||||
} else {
|
||||
return selectedVersions, nil
|
||||
return nil, fmt.Errorf("unable to find a matching version for \"%s\"", currentRequirement.Name)
|
||||
}
|
||||
return selectedVersions, nil
|
||||
}
|
||||
|
||||
func (versions PluginVersions) install() {
|
||||
func (pv PluginVersions) install() {
|
||||
anyInstalled := false
|
||||
currentlyInstalled := GetInstalledVersions(true)
|
||||
|
||||
for _, sel := range versions {
|
||||
for _, sel := range pv {
|
||||
if sel.pack.Name != CorePluginName {
|
||||
shouldInstall := true
|
||||
if pv := currentlyInstalled.find(sel.pack.Name); pv != nil {
|
||||
@@ -565,6 +564,7 @@ func UninstallPlugin(name string) {
|
||||
}
|
||||
}
|
||||
|
||||
// Install installs the plugin
|
||||
func (pl PluginPackage) Install() {
|
||||
selected, err := GetAllPluginPackages().Resolve(GetInstalledVersions(true), PluginDependencies{
|
||||
&PluginDependency{
|
||||
@@ -578,6 +578,7 @@ func (pl PluginPackage) Install() {
|
||||
selected.install()
|
||||
}
|
||||
|
||||
// UpdatePlugins updates the given plugins
|
||||
func UpdatePlugins(plugins []string) {
|
||||
// if no plugins are specified, update all installed plugins.
|
||||
if len(plugins) == 0 {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -21,10 +21,12 @@ var (
|
||||
)
|
||||
|
||||
// BeginSearch starts a search
|
||||
func BeginSearch() {
|
||||
func BeginSearch(searchStr string) {
|
||||
searchHistory = append(searchHistory, "")
|
||||
messenger.historyNum = len(searchHistory) - 1
|
||||
searching = true
|
||||
messenger.response = searchStr
|
||||
messenger.cursorx = Count(searchStr)
|
||||
messenger.hasPrompt = true
|
||||
messenger.Message("Find: ")
|
||||
}
|
||||
@@ -41,13 +43,27 @@ func EndSearch() {
|
||||
}
|
||||
}
|
||||
|
||||
// exit the search mode, reset active search phrase, and clear status bar
|
||||
func ExitSearch(v *View) {
|
||||
lastSearch = ""
|
||||
searching = false
|
||||
messenger.hasPrompt = false
|
||||
messenger.Clear()
|
||||
messenger.Reset()
|
||||
v.Cursor.ResetSelection()
|
||||
}
|
||||
|
||||
// HandleSearchEvent takes an event and a view and will do a real time match from the messenger's output
|
||||
// to the current buffer. It searches down the buffer.
|
||||
func HandleSearchEvent(event tcell.Event, v *View) {
|
||||
switch e := event.(type) {
|
||||
case *tcell.EventKey:
|
||||
switch e.Key() {
|
||||
case tcell.KeyCtrlQ, tcell.KeyCtrlC, tcell.KeyEscape, tcell.KeyEnter:
|
||||
case tcell.KeyEscape:
|
||||
// Exit the search mode
|
||||
ExitSearch(v)
|
||||
return
|
||||
case tcell.KeyCtrlQ, tcell.KeyCtrlC, tcell.KeyEnter:
|
||||
// Done
|
||||
EndSearch()
|
||||
return
|
||||
|
||||
@@ -178,8 +178,9 @@ func DefaultGlobalSettings() map[string]interface{} {
|
||||
"autoindent": true,
|
||||
"autosave": false,
|
||||
"colorcolumn": float64(0),
|
||||
"colorscheme": "zenburn",
|
||||
"colorscheme": "default",
|
||||
"cursorline": true,
|
||||
"eofnewline": false,
|
||||
"ignorecase": false,
|
||||
"indentchar": " ",
|
||||
"infobar": true,
|
||||
@@ -188,6 +189,7 @@ func DefaultGlobalSettings() map[string]interface{} {
|
||||
"saveundo": false,
|
||||
"scrollspeed": float64(2),
|
||||
"scrollmargin": float64(3),
|
||||
"softwrap": false,
|
||||
"statusline": true,
|
||||
"syntax": true,
|
||||
"tabsize": float64(4),
|
||||
@@ -207,6 +209,7 @@ func DefaultLocalSettings() map[string]interface{} {
|
||||
"autosave": false,
|
||||
"colorcolumn": float64(0),
|
||||
"cursorline": true,
|
||||
"eofnewline": false,
|
||||
"filetype": "Unknown",
|
||||
"ignorecase": false,
|
||||
"indentchar": " ",
|
||||
@@ -215,6 +218,7 @@ func DefaultLocalSettings() map[string]interface{} {
|
||||
"saveundo": false,
|
||||
"scrollspeed": float64(2),
|
||||
"scrollmargin": float64(3),
|
||||
"softwrap": false,
|
||||
"statusline": true,
|
||||
"syntax": true,
|
||||
"tabsize": float64(4),
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
package main
|
||||
|
||||
// SpltType specifies whether a split is horizontal or vertical
|
||||
type SplitType bool
|
||||
|
||||
const (
|
||||
VerticalSplit = false
|
||||
// VerticalSplit type
|
||||
VerticalSplit = false
|
||||
// HorizontalSplit type
|
||||
HorizontalSplit = true
|
||||
)
|
||||
|
||||
// A Node on the split tree
|
||||
type Node interface {
|
||||
VSplit(buf *Buffer)
|
||||
HSplit(buf *Buffer)
|
||||
String() string
|
||||
}
|
||||
|
||||
// A LeafNode is an actual split so it contains a view
|
||||
type LeafNode struct {
|
||||
view *View
|
||||
|
||||
parent *SplitTree
|
||||
}
|
||||
|
||||
// NewLeafNode returns a new leaf node containing the given view
|
||||
func NewLeafNode(v *View, parent *SplitTree) *LeafNode {
|
||||
n := new(LeafNode)
|
||||
n.view = v
|
||||
@@ -27,6 +33,7 @@ func NewLeafNode(v *View, parent *SplitTree) *LeafNode {
|
||||
return n
|
||||
}
|
||||
|
||||
// A SplitTree is a Node itself and it contains other nodes
|
||||
type SplitTree struct {
|
||||
kind SplitType
|
||||
|
||||
@@ -42,6 +49,7 @@ type SplitTree struct {
|
||||
tabNum int
|
||||
}
|
||||
|
||||
// VSplit creates a vertical split
|
||||
func (l *LeafNode) VSplit(buf *Buffer) {
|
||||
tab := tabs[l.parent.tabNum]
|
||||
if l.parent.kind == VerticalSplit {
|
||||
@@ -69,6 +77,7 @@ func (l *LeafNode) VSplit(buf *Buffer) {
|
||||
}
|
||||
}
|
||||
|
||||
// HSplit creates a horizontal split
|
||||
func (l *LeafNode) HSplit(buf *Buffer) {
|
||||
tab := tabs[l.parent.tabNum]
|
||||
if l.parent.kind == HorizontalSplit {
|
||||
@@ -96,6 +105,7 @@ func (l *LeafNode) HSplit(buf *Buffer) {
|
||||
}
|
||||
}
|
||||
|
||||
// Delete deletes a split
|
||||
func (l *LeafNode) Delete() {
|
||||
i := search(l.parent.children, l)
|
||||
|
||||
@@ -117,6 +127,7 @@ func (l *LeafNode) Delete() {
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup rearranges all the parents after a split has been deleted
|
||||
func (s *SplitTree) Cleanup() {
|
||||
for i, node := range s.children {
|
||||
if n, ok := node.(*SplitTree); ok {
|
||||
@@ -132,6 +143,7 @@ func (s *SplitTree) Cleanup() {
|
||||
}
|
||||
}
|
||||
|
||||
// ResizeSplits resizes all the splits correctly
|
||||
func (s *SplitTree) ResizeSplits() {
|
||||
for i, node := range s.children {
|
||||
if n, ok := node.(*LeafNode); ok {
|
||||
@@ -195,7 +207,10 @@ func findView(haystack []*View, needle *View) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// VSplit is here just to make SplitTree fit the Node interface
|
||||
func (s *SplitTree) VSplit(buf *Buffer) {}
|
||||
|
||||
// HSplit is here just to make SplitTree fit the Node interface
|
||||
func (s *SplitTree) HSplit(buf *Buffer) {}
|
||||
|
||||
func (s *SplitTree) String() string {
|
||||
|
||||
@@ -23,7 +23,7 @@ func Count(s string) int {
|
||||
return utf8.RuneCountInString(s)
|
||||
}
|
||||
|
||||
// NumOccurrences counts the number of occurences of a byte in a string
|
||||
// NumOccurrences counts the number of occurrences of a byte in a string
|
||||
func NumOccurrences(s string, c byte) int {
|
||||
var n int
|
||||
for i := 0; i < len(s); i++ {
|
||||
@@ -244,11 +244,11 @@ func FuncName(i interface{}) string {
|
||||
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
|
||||
}
|
||||
|
||||
// SplitCommandArgs seperates multiple command arguments which may be quoted.
|
||||
// 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 = nil
|
||||
var curQuote *bytes.Buffer
|
||||
|
||||
curArg := new(bytes.Buffer)
|
||||
escape := false
|
||||
|
||||
@@ -27,14 +27,11 @@ type View struct {
|
||||
Cursor *Cursor
|
||||
|
||||
// The topmost line, used for vertical scrolling
|
||||
Topline int
|
||||
Topline int
|
||||
Bottomline int
|
||||
// The leftmost column, used for horizontal scrolling
|
||||
leftCol int
|
||||
|
||||
// Percentage of the terminal window that this view takes up (from 0 to 100)
|
||||
widthPercent int
|
||||
heightPercent int
|
||||
|
||||
// Specifies whether or not this view holds a help buffer
|
||||
Type ViewType
|
||||
|
||||
@@ -132,6 +129,7 @@ func NewViewWidthHeight(buf *Buffer, w, h int) *View {
|
||||
return v
|
||||
}
|
||||
|
||||
// ToggleStatusLine creates an extra row for the statusline if necessary
|
||||
func (v *View) ToggleStatusLine() {
|
||||
if v.Buf.Settings["statusline"].(bool) {
|
||||
v.height--
|
||||
@@ -140,6 +138,7 @@ func (v *View) ToggleStatusLine() {
|
||||
}
|
||||
}
|
||||
|
||||
// ToggleTabbar creates an extra row for the tabbar if necessary
|
||||
func (v *View) ToggleTabbar() {
|
||||
if len(tabs) > 1 {
|
||||
if v.y == 0 {
|
||||
@@ -237,6 +236,7 @@ func (v *View) OpenBuffer(buf *Buffer) {
|
||||
v.lastClickTime = time.Time{}
|
||||
}
|
||||
|
||||
// Open opens the given file in the view
|
||||
func (v *View) Open(filename string) {
|
||||
home, _ := homedir.Dir()
|
||||
filename = strings.Replace(filename, "~", home, 1)
|
||||
@@ -284,9 +284,49 @@ func (v *View) VSplit(buf *Buffer) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// GetSoftWrapLocation gets the location of a visual click on the screen and converts it to col,line
|
||||
func (v *View) GetSoftWrapLocation(vx, vy int) (int, int) {
|
||||
if !v.Buf.Settings["softwrap"].(bool) {
|
||||
vx = v.Cursor.GetCharPosInLine(vy, vx)
|
||||
return vx, vy
|
||||
}
|
||||
|
||||
screenX, screenY := 0, v.Topline
|
||||
for lineN := v.Topline; lineN < v.Bottomline; lineN++ {
|
||||
line := v.Buf.Line(lineN)
|
||||
|
||||
colN := 0
|
||||
for _, ch := range line {
|
||||
if screenX >= v.width-v.lineNumOffset {
|
||||
screenX = 0
|
||||
screenY++
|
||||
}
|
||||
|
||||
if screenX == vx && screenY == vy {
|
||||
return colN, lineN
|
||||
}
|
||||
|
||||
if ch == '\t' {
|
||||
screenX += int(v.Buf.Settings["tabsize"].(float64)) - 1
|
||||
}
|
||||
|
||||
screenX++
|
||||
colN++
|
||||
}
|
||||
if screenY == vy {
|
||||
return colN, lineN
|
||||
}
|
||||
screenX = 0
|
||||
screenY++
|
||||
}
|
||||
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
// Relocate moves the view window so that the cursor is in view
|
||||
// This is useful if the user has scrolled far away, and then starts typing
|
||||
func (v *View) Relocate() bool {
|
||||
height := v.Bottomline - v.Topline
|
||||
ret := false
|
||||
cy := v.Cursor.Y
|
||||
scrollmargin := int(v.Buf.Settings["scrollmargin"].(float64))
|
||||
@@ -297,22 +337,24 @@ func (v *View) Relocate() bool {
|
||||
v.Topline = cy
|
||||
ret = true
|
||||
}
|
||||
if cy > v.Topline+v.height-1-scrollmargin && cy < v.Buf.NumLines-scrollmargin {
|
||||
v.Topline = cy - v.height + 1 + scrollmargin
|
||||
if cy > v.Topline+height-1-scrollmargin && cy < v.Buf.NumLines-scrollmargin {
|
||||
v.Topline = cy - height + 1 + scrollmargin
|
||||
ret = true
|
||||
} else if cy >= v.Buf.NumLines-scrollmargin && cy > v.height {
|
||||
v.Topline = v.Buf.NumLines - v.height
|
||||
} else if cy >= v.Buf.NumLines-scrollmargin && cy > height {
|
||||
v.Topline = v.Buf.NumLines - height
|
||||
ret = true
|
||||
}
|
||||
|
||||
cx := v.Cursor.GetVisualX()
|
||||
if cx < v.leftCol {
|
||||
v.leftCol = cx
|
||||
ret = true
|
||||
}
|
||||
if cx+v.lineNumOffset+1 > v.leftCol+v.width {
|
||||
v.leftCol = cx - v.width + v.lineNumOffset + 1
|
||||
ret = true
|
||||
if !v.Buf.Settings["softwrap"].(bool) {
|
||||
cx := v.Cursor.GetVisualX()
|
||||
if cx < v.leftCol {
|
||||
v.leftCol = cx
|
||||
ret = true
|
||||
}
|
||||
if cx+v.lineNumOffset+1 > v.leftCol+v.width {
|
||||
v.leftCol = cx - v.width + v.lineNumOffset + 1
|
||||
ret = true
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
@@ -334,7 +376,8 @@ func (v *View) MoveToMouseClick(x, y int) {
|
||||
x = 0
|
||||
}
|
||||
|
||||
x = v.Cursor.GetCharPosInLine(y, x)
|
||||
x, y = v.GetSoftWrapLocation(x, y)
|
||||
// x = v.Cursor.GetCharPosInLine(y, x)
|
||||
if x > Count(v.Buf.Line(y)) {
|
||||
x = Count(v.Buf.Line(y))
|
||||
}
|
||||
@@ -608,17 +651,22 @@ func (v *View) DisplayView() {
|
||||
}
|
||||
|
||||
// These represent the current screen coordinates
|
||||
screenX, screenY := 0, 0
|
||||
screenX, screenY := v.x, v.y-1
|
||||
|
||||
highlightStyle := defStyle
|
||||
curLineN := 0
|
||||
|
||||
// ViewLine is the current line from the top of the viewport
|
||||
for viewLine := 0; viewLine < v.height; viewLine++ {
|
||||
screenY = v.y + viewLine
|
||||
screenY++
|
||||
screenX = v.x
|
||||
|
||||
// This is the current line number of the buffer that we are drawing
|
||||
curLineN := viewLine + v.Topline
|
||||
curLineN = viewLine + v.Topline
|
||||
|
||||
if screenY-v.y >= v.height {
|
||||
break
|
||||
}
|
||||
|
||||
if v.x != 0 {
|
||||
// Draw the split divider
|
||||
@@ -683,9 +731,9 @@ func (v *View) DisplayView() {
|
||||
}
|
||||
}
|
||||
|
||||
lineNumStyle := defStyle
|
||||
if v.Buf.Settings["ruler"] == true {
|
||||
// Write the line number
|
||||
lineNumStyle := defStyle
|
||||
if style, ok := colorscheme["line-number"]; ok {
|
||||
lineNumStyle = style
|
||||
}
|
||||
@@ -718,6 +766,20 @@ func (v *View) DisplayView() {
|
||||
strWidth := 0
|
||||
tabSize := int(v.Buf.Settings["tabsize"].(float64))
|
||||
for _, ch := range line {
|
||||
if v.Buf.Settings["softwrap"].(bool) {
|
||||
if screenX-v.x >= v.width {
|
||||
screenY++
|
||||
for i := 0; i < v.lineNumOffset; i++ {
|
||||
screen.SetContent(v.x+i, screenY, ' ', nil, lineNumStyle)
|
||||
}
|
||||
screenX = v.x + v.lineNumOffset
|
||||
}
|
||||
}
|
||||
|
||||
if tabs[curTab].curView == v.Num && !v.Cursor.HasSelection() && v.Cursor.Y == curLineN && colN == v.Cursor.X {
|
||||
v.DisplayCursor(screenX-v.leftCol, screenY)
|
||||
}
|
||||
|
||||
lineStyle := defStyle
|
||||
|
||||
if v.Buf.Settings["syntax"].(bool) {
|
||||
@@ -808,6 +870,10 @@ func (v *View) DisplayView() {
|
||||
}
|
||||
// Here we are at a newline
|
||||
|
||||
if tabs[curTab].curView == v.Num && !v.Cursor.HasSelection() && v.Cursor.Y == curLineN && colN == v.Cursor.X {
|
||||
v.DisplayCursor(screenX-v.leftCol, screenY)
|
||||
}
|
||||
|
||||
// The newline may be selected, in which case we should draw the selection style
|
||||
// with a space to represent it
|
||||
if v.Cursor.HasSelection() &&
|
||||
@@ -845,23 +911,24 @@ func (v *View) DisplayView() {
|
||||
}
|
||||
}
|
||||
}
|
||||
v.Bottomline = curLineN
|
||||
if !v.Buf.Settings["softwrap"].(bool) {
|
||||
v.Bottomline++
|
||||
}
|
||||
}
|
||||
|
||||
// DisplayCursor draws the current buffer's cursor to the screen
|
||||
func (v *View) DisplayCursor() {
|
||||
// Don't draw the cursor if it is out of the viewport or if it has a selection
|
||||
if (v.Cursor.Y-v.Topline < 0 || v.Cursor.Y-v.Topline > v.height-1) || v.Cursor.HasSelection() {
|
||||
screen.HideCursor()
|
||||
} else {
|
||||
screen.ShowCursor(v.x+v.Cursor.GetVisualX()+v.lineNumOffset-v.leftCol, v.Cursor.Y-v.Topline+v.y)
|
||||
}
|
||||
func (v *View) DisplayCursor(x, y int) {
|
||||
// screen.ShowCursor(v.x+v.Cursor.GetVisualX()+v.lineNumOffset-v.leftCol, y)
|
||||
screen.ShowCursor(x, y)
|
||||
}
|
||||
|
||||
// Display renders the view, the cursor, and statusline
|
||||
func (v *View) Display() {
|
||||
v.DisplayView()
|
||||
if v.Num == tabs[curTab].curView {
|
||||
v.DisplayCursor()
|
||||
// Don't draw the cursor if it is out of the viewport or if it has a selection
|
||||
if (v.Cursor.Y-v.Topline < 0 || v.Cursor.Y-v.Topline > v.height-1) || v.Cursor.HasSelection() {
|
||||
screen.HideCursor()
|
||||
}
|
||||
_, screenH := screen.Size()
|
||||
if v.Buf.Settings["statusline"].(bool) {
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
color-link default "188,237"
|
||||
color-link comment "108,237"
|
||||
color-link constant.string "174,237"
|
||||
color-link constant.number "116,237"
|
||||
color-link constant "181,237"
|
||||
color-link identifier "223,237"
|
||||
color-link statement "223,237"
|
||||
color-link preproc "223,237"
|
||||
color-link type "187,237"
|
||||
color-link special "181,237"
|
||||
color-link underlined "188,237"
|
||||
color-link error "115,236"
|
||||
color-link todo "bold 254,237"
|
||||
color-link statusline "186,236"
|
||||
color-link indent-char "238,237"
|
||||
color-link line-number "188,238"
|
||||
color-link gutter-error "237,174"
|
||||
color-link gutter-warning "174,237"
|
||||
color-link cursor-line "238"
|
||||
color-link current-line-number "188,237"
|
||||
# This is the monokai colorscheme
|
||||
color-link default "#F8F8F2,#282828"
|
||||
color-link comment "#75715E,#282828"
|
||||
color-link identifier "#66D9EF,#282828"
|
||||
color-link constant "#AE81FF,#282828"
|
||||
color-link constant.string "#E6DB74,#282828"
|
||||
color-link statement "#F92672,#282828"
|
||||
color-link preproc "#CB4B16,#282828"
|
||||
color-link type "#66D9EF,#282828"
|
||||
color-link special "#A6E22E,#282828"
|
||||
color-link underlined "#D33682,#282828"
|
||||
color-link error "bold #CB4B16,#282828"
|
||||
color-link todo "bold #D33682,#282828"
|
||||
color-link statusline "#282828,#F8F8F2"
|
||||
color-link indent-char "#505050,#282828"
|
||||
color-link line-number "#AAAAAA,#323232"
|
||||
color-link current-line-number "#AAAAAA,#282828"
|
||||
color-link gutter-error "#CB4B16,#282828"
|
||||
color-link gutter-warning "#E6DB74,#282828"
|
||||
color-link cursor-line "#323232"
|
||||
color-link color-column "#323232"
|
||||
|
||||
@@ -12,9 +12,12 @@ 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
|
||||
|
||||
* zenburn: this is micro's default colorscheme because it looks very good
|
||||
and works in 256 color terminals.
|
||||
this colorscheme also has the name 'default'
|
||||
* 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.
|
||||
@@ -23,10 +26,6 @@ Micro comes with a number of colorschemes by default. Here is the list:
|
||||
make sure your terminal supports true color before using it and that the
|
||||
MICRO_TRUECOLOR environment variable is set to 1 before starting micro.
|
||||
|
||||
* 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.
|
||||
|
||||
* atom-dark-tc: this colorscheme is based off of Atom's "dark" colorscheme.
|
||||
It requires true color to look good.
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ Here are the possible commands that you can use.
|
||||
You can also see more information about the plugin manager
|
||||
in the `Plugin Manager` section of the `plugins` help topic.
|
||||
|
||||
* `reload`: reloads all runtime files.
|
||||
|
||||
---
|
||||
|
||||
The following commands are provided by the default plugins:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Keybindings
|
||||
|
||||
Here are the default keybindings in json form which is also how
|
||||
you can rebind them to your liking.
|
||||
Here are the default keybindings in json format. You can rebind them to your liking, following the same format.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -17,6 +16,8 @@ you can rebind them to your liking.
|
||||
"AltRight": "WordRight",
|
||||
"AltShiftRight": "SelectWordRight",
|
||||
"AltShiftLeft": "SelectWordLeft",
|
||||
"AltUp": "MoveLinesUp",
|
||||
"AltDown": "MoveLinesDown",
|
||||
"CtrlLeft": "StartOfLine",
|
||||
"CtrlRight": "EndOfLine",
|
||||
"CtrlShiftLeft": "SelectToStartOfLine",
|
||||
@@ -80,7 +81,7 @@ you can rebind them to your liking.
|
||||
"F4": "Quit",
|
||||
"F7": "Find",
|
||||
"F10": "Quit",
|
||||
"Esc": "Quit",
|
||||
"Esc": "Escape",
|
||||
}
|
||||
```
|
||||
|
||||
@@ -140,6 +141,8 @@ WordRight
|
||||
WordLeft
|
||||
SelectWordRight
|
||||
SelectWordLeft
|
||||
MoveLinesUp
|
||||
MoveLinesDown
|
||||
DeleteWordRight
|
||||
DeleteWordLeft
|
||||
SelectToStartOfLine
|
||||
|
||||
@@ -28,6 +28,10 @@ Here are the options that you can set:
|
||||
|
||||
default value: `0`
|
||||
|
||||
* `eofnewline`: micro will automatically add a newline to the file.
|
||||
|
||||
default value: `false`
|
||||
|
||||
* `tabsize`: sets the tab size to `option`
|
||||
|
||||
default value: `4`
|
||||
@@ -93,6 +97,10 @@ Here are the options that you can set:
|
||||
|
||||
default value: `2`
|
||||
|
||||
* `softwrap`: should micro wrap lines that are too long to fit on the screen
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `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,
|
||||
|
||||
@@ -2,25 +2,19 @@
|
||||
syntax "dockerfile" "Dockerfile[^/]*$" "\.dockerfile$"
|
||||
|
||||
## Keywords
|
||||
red (i) "^(FROM|MAINTAINER|RUN|CMD|LABEL|EXPOSE|ENV|ADD|COPY|ENTRYPOINT|VOLUME|USER|WORKDIR|ONBUILD)[[:space:]]"
|
||||
color keyword (i) "^(FROM|MAINTAINER|RUN|CMD|LABEL|EXPOSE|ENV|ADD|COPY|ENTRYPOINT|VOLUME|USER|WORKDIR|ONBUILD|ARG|HEALTHCHECK|STOPSIGNAL|SHELL)[[:space:]]"
|
||||
|
||||
## Brackets & parenthesis
|
||||
color brightgreen "(\(|\)|\[|\])"
|
||||
color statement "(\(|\)|\[|\])"
|
||||
|
||||
## Double ampersand
|
||||
color brightmagenta "&&"
|
||||
color special "&&"
|
||||
|
||||
## Comments
|
||||
cyan (i) "^[[:space:]]*#.*$"
|
||||
|
||||
## Blank space at EOL
|
||||
color ,green "[[:space:]]+$"
|
||||
color comment (i) "^[[:space:]]*#.*$"
|
||||
|
||||
## Strings, single-quoted
|
||||
color brightwhite "'([^']|(\\'))*'" "%[qw]\{[^}]*\}" "%[qw]\([^)]*\)" "%[qw]<[^>]*>" "%[qw]\[[^]]*\]" "%[qw]\$[^$]*\$" "%[qw]\^[^^]*\^" "%[qw]![^!]*!"
|
||||
color constant.string "'([^']|(\\'))*'" "%[qw]\{[^}]*\}" "%[qw]\([^)]*\)" "%[qw]<[^>]*>" "%[qw]\[[^]]*\]" "%[qw]\$[^$]*\$" "%[qw]\^[^^]*\^" "%[qw]![^!]*!"
|
||||
|
||||
## Strings, double-quoted
|
||||
color brightwhite ""([^"]|(\\"))*"" "%[QW]?\{[^}]*\}" "%[QW]?\([^)]*\)" "%[QW]?<[^>]*>" "%[QW]?\[[^]]*\]" "%[QW]?\$[^$]*\$" "%[QW]?\^[^^]*\^" "%[QW]?![^!]*!"
|
||||
|
||||
## Single and double quotes
|
||||
color brightyellow "('|\")"
|
||||
color constant.string ""([^"]|(\\"))*"" "%[QW]?\{[^}]*\}" "%[QW]?\([^)]*\)" "%[QW]?<[^>]*>" "%[QW]?\[[^]]*\]" "%[QW]?\$[^$]*\$" "%[QW]?\^[^^]*\^" "%[QW]?![^!]*!"
|
||||
|
||||
@@ -4,13 +4,15 @@ color constant.number "\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[
|
||||
color constant.number "\b[-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([EePp][+-]?[0-9]+)?[fFlL]?"
|
||||
color constant.number "\b[-+]?([0-9]+[EePp][+-]?[0-9]+)[fFlL]?"
|
||||
color identifier "[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[(]"
|
||||
color statement "\b(break|case|catch|continue|default|delete|do|else|finally)\b"
|
||||
color statement "\b(declare|interface|import|export|from|for|function|get|if|in|instanceof|new|return|set|switch)\b"
|
||||
color statement "\b(switch|this|throw|try|typeof|var|void|while|with|async|await)\b"
|
||||
color constant "\b(null|undefined|NaN)\b"
|
||||
color constant "\b(true|false)\b"
|
||||
color type "\b(Array|Boolean|Date|Enumerator|Error|Function|Math|string|number|boolean|any)\b"
|
||||
color type "\b(Number|Object|RegExp|String)\b"
|
||||
color statement "\b(abstract|as|async|await|break|case|catch|class|const|constructor|continue)\b"
|
||||
color statement "\b(debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from)\b"
|
||||
color statement "\b(function|get|if|implements|import|in|instanceof|interface|is|let|module|namespace)\b"
|
||||
color statement "\b(new|of|package|private|protected|public|require|return|set|static|super|switch)\b"
|
||||
color statement "\b(this|throw|try|type|typeof|var|void|while|with|yield)\b"
|
||||
color constant "\b(false|true|null|undefined|NaN)\b"
|
||||
color type "\b(Array|Boolean|Date|Enumerator|Error|Function|Math)\b"
|
||||
color type "\b(Number|Object|RegExp|String|Symbol)\b"
|
||||
color type "\b(any|boolean|never|number|string|symbol)\b"
|
||||
color statement "[-+/*=<>!~%?:&|]"
|
||||
color constant "/[^*]([^/]|(\\/))*[^\\]/[gim]*"
|
||||
color constant "\\[0-7][0-7]?[0-7]?|\\x[0-9a-fA-F]+|\\[bfnrt'"\?\\]"
|
||||
|
||||
@@ -6,6 +6,7 @@ color constant "\b(YES|yes|Y|y|ON|on|NO|no|N|n|OFF|off)\b"
|
||||
color constant "\b(true|false)\b"
|
||||
color statement ":[[:space:]]" "\[" "\]" ":[[:space:]]+[|>]" "^[[:space:]]*- "
|
||||
color identifier "[[:space:]][\*&][A-Za-z0-9]+"
|
||||
color type "([-\w]+:\s+)|([-\w]+:$)"
|
||||
color constant.string ""(\\.|[^"])*"|'(\\.|[^'])*'"
|
||||
color comment "(^|[[:space:]])#([^{].*)?$"
|
||||
color special "^---" "^\.\.\." "^%YAML" "^%TAG"
|
||||
|
||||
@@ -32,7 +32,7 @@ func main() {
|
||||
version, err := semver.ParseTolerant(versionStr)
|
||||
if err != nil {
|
||||
// no version tag found so just return what ever we can find.
|
||||
fmt.Println(getTag())
|
||||
fmt.Println("0.0.0-unknown")
|
||||
return
|
||||
}
|
||||
// Get the tag of the current revision.
|
||||
|
||||
@@ -7,54 +7,56 @@ cp LICENSE micro-$1
|
||||
cp README.md micro-$1
|
||||
|
||||
HASH="$(git rev-parse --short HEAD)"
|
||||
VERSION="$(go run tools/build-version.go)"
|
||||
DATE="$(go run tools/build-date.go)"
|
||||
|
||||
# Mac
|
||||
echo "OSX 64"
|
||||
GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$(date -u '+%B %d, %Y')'" -o micro-$1/micro ./cmd/micro
|
||||
GOOS=darwin 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-osx.tar.gz micro-$1
|
||||
mv micro-$1-osx.tar.gz binaries
|
||||
|
||||
# Linux
|
||||
echo "Linux 64"
|
||||
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$(date -u '+%B %d, %Y')'" -o micro-$1/micro ./cmd/micro
|
||||
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 -u '+%B %d, %Y')'" -o micro-$1/micro ./cmd/micro
|
||||
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 -u '+%B %d, %Y')'" -o micro-$1/micro ./cmd/micro
|
||||
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
|
||||
|
||||
# NetBSD
|
||||
echo "NetBSD 64"
|
||||
GOOS=netbsd GOARCH=amd64 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$(date -u '+%B %d, %Y')'" -o micro-$1/micro ./cmd/micro
|
||||
GOOS=netbsd 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-netbsd64.tar.gz micro-$1
|
||||
mv micro-$1-netbsd64.tar.gz binaries
|
||||
echo "NetBSD 32"
|
||||
GOOS=netbsd GOARCH=386 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$(date -u '+%B %d, %Y')'" -o micro-$1/micro ./cmd/micro
|
||||
GOOS=netbsd 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-netbsd32.tar.gz micro-$1
|
||||
mv micro-$1-netbsd32.tar.gz binaries
|
||||
|
||||
# OpenBSD
|
||||
echo "OpenBSD 64"
|
||||
GOOS=openbsd GOARCH=amd64 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$(date -u '+%B %d, %Y')'" -o micro-$1/micro ./cmd/micro
|
||||
GOOS=openbsd 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-openbsd64.tar.gz micro-$1
|
||||
mv micro-$1-openbsd64.tar.gz binaries
|
||||
echo "OpenBSD 32"
|
||||
GOOS=openbsd GOARCH=386 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$(date -u '+%B %d, %Y')'" -o micro-$1/micro ./cmd/micro
|
||||
GOOS=openbsd 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-openbsd32.tar.gz micro-$1
|
||||
mv micro-$1-openbsd32.tar.gz binaries
|
||||
|
||||
# FreeBSD
|
||||
echo "FreeBSD 64"
|
||||
GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$(date -u '+%B %d, %Y')'" -o micro-$1/micro ./cmd/micro
|
||||
GOOS=freebsd 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-freebsd64.tar.gz micro-$1
|
||||
mv micro-$1-freebsd64.tar.gz binaries
|
||||
echo "FreeBSD 32"
|
||||
GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$(date -u '+%B %d, %Y')'" -o micro-$1/micro ./cmd/micro
|
||||
GOOS=freebsd 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-freebsd32.tar.gz micro-$1
|
||||
mv micro-$1-freebsd32.tar.gz binaries
|
||||
|
||||
@@ -62,11 +64,11 @@ rm micro-$1/micro
|
||||
|
||||
# Windows
|
||||
echo "Windows 64"
|
||||
GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$(date -u '+%B %d, %Y')'" -o micro-$1/micro.exe ./cmd/micro
|
||||
GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$DATE'" -o micro-$1/micro.exe ./cmd/micro
|
||||
zip -r -q -T micro-$1-win64.zip micro-$1
|
||||
mv micro-$1-win64.zip binaries
|
||||
echo "Windows 32"
|
||||
GOOS=windows GOARCH=386 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$(date -u '+%B %d, %Y')'" -o micro-$1/micro.exe ./cmd/micro
|
||||
GOOS=windows GOARCH=386 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$DATE'" -o micro-$1/micro.exe ./cmd/micro
|
||||
zip -r -q -T micro-$1-win32.zip micro-$1
|
||||
mv micro-$1-win32.zip binaries
|
||||
|
||||
|
||||
Reference in New Issue
Block a user