Compare commits

..

52 Commits

Author SHA1 Message Date
Zachary Yedidia
c04a4ba604 Minor update 2016-10-24 08:03:00 -04:00
Zachary Yedidia
63ccbc1ebd Add eofnewline option
Closes #429

Enable with '> set eofnewline on'
2016-10-23 18:37:29 -04:00
Zachary Yedidia
ee553b7830 Add reload command
Closes #427
2016-10-21 11:51:36 -04:00
Zachary Yedidia
97fc52093f Add website to readme 2016-10-21 10:57:37 -04:00
Zachary Yedidia
49397039e0 Update runtime 2016-10-19 10:34:09 -04:00
Zachary Yedidia
efe1ab5db6 Merge pull request #425 from adrianvoica/master
Updated TypeScript with all the reserved words and new types
2016-10-19 07:26:49 -04:00
Zachary Yedidia
daeffdc81b Merge pull request #423 from ulrichSchreiner/master
add additional Dockerfile keywords
2016-10-19 07:26:36 -04:00
Zachary Yedidia
30083c4d0f Merge pull request #424 from ulrichSchreiner/yaml-highlighter
highlight yaml dicts as types
2016-10-19 07:26:23 -04:00
Adrian Voica
56e616d5bf Updated TypeScript with all the reserved words and new types 2016-10-19 11:54:49 +03:00
Ulrich Schreiner
112da0b8c6 highlight yaml dicts as types 2016-10-19 09:35:03 +02:00
Ulrich Schreiner
163a3993bd add additional Dockerfile keywords 2016-10-19 06:34:50 +02:00
Zachary Yedidia
1b9bb31dd6 Cleanup and add more comments 2016-10-18 11:12:28 -04:00
Zachary Yedidia
8db3b22411 Merge 2016-10-18 08:58:31 -04:00
Zachary Yedidia
4aae5ca451 Fix dockerfile syntax file
Fixes #421
2016-10-18 08:58:09 -04:00
Zachary Yedidia
d3a3b7a8cd Merge pull request #417 from jncraton/outdent-line
Added OutdentLine action
2016-10-16 09:55:24 -04:00
Jon Craton
cc9342df9d Added OutdentLine action 2016-10-15 12:47:15 -04:00
Jon Craton
fe0dce0960 Added IndentString method on Buffer (#415)
* Added IndentString function to retrun the string used for indentation (n-spaces or a tab) based on buffer settings

* Combined redundant  statements

* Removed duplicate leading whitespace check

* Better IndentString description

* Fixed remainder logic that I broke
2016-10-15 10:09:20 -04:00
Zachary Yedidia
766f836952 Merge pull request #416 from jncraton/duplicate-selection
DuplicateLine duplicates current selection if there is text selected
2016-10-15 10:09:08 -04:00
Jon Craton
78b0aac5ec DuplicateLine now duplicates the current selection if there is text selected 2016-10-14 22:22:48 -04:00
Jon Craton
690627a338 Refactored IndentSelection and OutdentSelection to remove duplicate code (#414)
* Refactored indent selection

* Refactored OutdentSelection

* Refactored to use x and y instead of line and j
2016-10-14 16:52:55 -04:00
Zachary Yedidia
25ced4c075 Merge pull request #412 from ilius/pr04.keybindings_help_fixes
Fixes in keybindings.md
2016-10-14 07:37:45 -04:00
Zachary Yedidia
771b5333aa Merge pull request #411 from zenlc2000/master
Reworded first sentence to make it clearer.
2016-10-14 07:35:19 -04:00
Saeed Rasooli
ae72608c5d Bugfix: keybindings.md: fix bad json syntax, due to #407 2016-10-14 14:29:58 +03:30
Saeed Rasooli
2e778a2a8e update keybindings.md due to PR #409 2016-10-14 14:29:58 +03:30
zenlc2000
bc9e811797 Reworded first sentence to make it clearer. 2016-10-13 23:10:37 -06:00
Zachary Yedidia
4db7f33eaf More fixes to search and replace 2016-10-13 20:47:33 -04:00
Zachary Yedidia
d3c5e3ab47 Improvements for softwrap mouse support 2016-10-13 17:09:15 -04:00
Zachary Yedidia
b13c6c4892 Fix problem with regexes in search and replace
Fixes #410
2016-10-13 14:59:57 -04:00
Zachary Yedidia
c50dda244b Fix mouse support with soft wrap 2016-10-13 14:26:45 -04:00
Zachary Yedidia
3fdc2ca0da Always use the selection as search term when using quick search 2016-10-13 12:12:55 -04:00
Zachary Yedidia
6b7ca3c559 Merge pull request #409 from ilius/pr02.improve_search_escape
Improve Search behaviour, and Escape key behaviour
2016-10-13 12:10:11 -04:00
Zachary Yedidia
5c2a2b1b7e Fix problem with horizontal scrolling 2016-10-12 22:05:24 -04:00
Zachary Yedidia
69e45f9a4f Fix problem causing hsplits not to display 2016-10-12 22:03:16 -04:00
Saeed Rasooli
127ebc15b9 Improvement: improve Search behaviour, and Escape key behaviour 2016-10-13 00:49:43 +03:30
Zachary Yedidia
ea1de18326 Add docs 2016-10-12 16:34:34 -04:00
Zachary Yedidia
edd25c68ee Fix glitch with bottomline when softwrap is disabled 2016-10-12 16:30:32 -04:00
Zachary Yedidia
e30a4139e6 Add softwrap 2016-10-12 16:24:00 -04:00
Saeed Rasooli
546acfd21d Fixes in last PR: MoveLinesUp and MoveLinesDown (#408)
* Bugfix: fix panic in MoveLinesUp when moving up the *last* line

* Bugfix: don't panic in Buffer.Line if index is out or range

* clean MoveLinesDown since it won't work for the last line anyway, add comment

* Cleanup: replace spaces with tabs in MoveLinesUp and MoveLinesDown
2016-10-12 11:38:44 -04:00
Zachary Yedidia
d27690b8c6 Merge 2016-10-12 14:47:40 +00:00
Zachary Yedidia
adc56e60fc Use build-date.go in cross compilation script 2016-10-12 14:47:29 +00:00
Zachary Yedidia
266ce5c43b Merge pull request #407 from ilius/pr01.move_up_down
Feature: add MoveLinesUp (Alt + Up) and MoveLinesDown (Alt + Down) actions
2016-10-12 09:51:30 -04:00
Saeed Rasooli
0bf07eadcc Improvement: move MoveLinesUp and MoveLinesDown to Buffer
enables Undo/Redo with EventHandler, #407
2016-10-12 08:15:46 +03:30
Saeed Rasooli
e4386d9398 add help for MoveLinesUp and MoveLinesDown 2016-10-12 08:15:46 +03:30
Saeed Rasooli
c1dd403ab9 Feature: add MoveLinesUp (Alt + Up) and MoveLinesDown (Alt + Down) actions 2016-10-12 08:15:46 +03:30
Zachary Yedidia
0e4f700527 Update installation instructions 2016-10-11 18:21:06 -04:00
Zachary Yedidia
a48c991958 Return 0.0.0-unknown version if building without a git repo 2016-10-11 15:25:39 -04:00
Zachary Yedidia
cbc250b7d0 Improve Makefile
Now you can use 'make update' which will update micro and all the
dependencies (but won't rebuild). The makefile also now supports
having a $GOBIN variable and having multiple directories in your
$GOPATH.
2016-10-11 11:07:53 -04:00
Zachary Yedidia
b27ef219a0 Update readme installation instructions 2016-10-11 09:34:49 -04:00
Zachary Yedidia
d163637fa8 Update docs 2016-10-11 09:13:03 -04:00
Zachary Yedidia
905d4d7020 Make monokai the default colorscheme
Monokai is a better default colorscheme because it has a better 16
color approximation than zenburn. On 16 color terminals, it looks like
zenburn is not syntax highlighting anything.
2016-10-11 09:09:56 -04:00
Zachary Yedidia
f85dd77036 Merge 2016-10-10 21:44:48 -04:00
Zachary Yedidia
8f5f8ffdd6 Fix tabstop sizing with mix of tabs and spaces
Fixes #404
2016-10-10 21:44:16 -04:00
24 changed files with 591 additions and 268 deletions

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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",
}
}

View File

@@ -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},
)
}

View File

@@ -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
}
}
}

View File

@@ -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))

View File

@@ -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

View File

@@ -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

View File

@@ -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),

View File

@@ -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 {

View File

@@ -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

View File

@@ -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) {

View File

@@ -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"

View File

@@ -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.

View File

@@ -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:

View File

@@ -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

View File

@@ -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,

View 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]?![^!]*!"

View File

@@ -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'"\?\\]"

View File

@@ -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"

View File

@@ -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.

View File

@@ -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