diff --git a/README.md b/README.md index 8a13a875..23c2c591 100644 --- a/README.md +++ b/README.md @@ -4,28 +4,50 @@ [![Go Report Card](http://goreportcard.com/badge/zyedidia/micro)](http://goreportcard.com/report/zyedidia/micro) [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/zyedidia/micro/blob/master/LICENSE) -> Micro is a work in progress, not suitable for use yet. +> Micro is very much a work in progress Micro is a command line text editor that aims to be easy to use and intuitive, while also taking advantage of the full capabilities of modern terminals. +Here is a picture of micro editing its source code. + +![Screenshot](./screenshot.png) + # Features * Easy to use * Common keybindings (ctrl-s, ctrl-c, ctrl-v, ctrl-z...) * Extremely good mouse support -* True color support * Cross platform -* Fast and efficient * Syntax highlighting (in over [75 languages](runtime/syntax)!) +* Colorscheme support +* True color support (set the `MICRO_TRUECOLOR` env variable to 1 to enable it) +* Search and replace +* Undo and redo +* Small and simple +* Configurable -Not all of this is implemented yet -- see [progress](#progress) +If you'd like to see what has been implemented, and what I plan on implementing soon-ish, see the [todo list](todolist.md) # Installation -Installation is simple. For now you must build from source, although in the future binaries will be provided. +### Prebuilt binaries -Make sure your `GOPATH` is set. +| Download | +| --- | +| [Mac OS X](http://zbyedidia.webfactional.com/micro/binaries/micro-osx.tar.gz) | +| [64 bit Linux](http://zbyedidia.webfactional.com/micro/binaries/micro-linux64.tar.gz) | +| [32 bit Linux](http://zbyedidia.webfactional.com/micro/binaries/micro-linux32.tar.gz) | +| [Arm Linux](http://zbyedidia.webfactional.com/micro/binaries/micro-linux-arm.tar.gz) | + +Once you have downloaded the file, you can install the runtime files by running `./install.sh` +in the directory you downloaded. This will place all the runtime files in `~/.micro`. + +To run the micro binary just run `./bin/micro` (you may want to place the binary on your path for ease of use). + +### Building from source + +Micro is made in Go so you must have Go installed on your system to build it, and make sure your `GOPATH` is set. ``` $ git clone https://github.com/zyedidia/micro @@ -37,6 +59,54 @@ This will build micro and put the binary in the current directory. It will also Alternatively you can use `make install` instead of `make` if you want the binary to be added to you `GOBIN` (make sure that it is set). -# Progress +# Usage -Micro is very much a work in progress right now. To see what has and hasn't been done yet, see the [todolist](todolist.md) +Once you have built the editor, simply start it by running `micro path/to/file.txt` or simply `micro` to open an empty buffer. + +Micro also supports creating buffers from `stdin`: + +``` +$ ifconfig | micro +``` + +You can move the cursor around with the arrow keys and mouse. + +#### Keybindings + +* Ctrl-q: Quit +* Ctrl-s: Save +* Ctrl-o: Open file +* Ctrl-z: Undo +* Ctrl-y: Redo +* Ctrl-f: Find +* Ctrl-a: Select all +* Ctrl-c: Copy +* Ctrl-x: Cut +* Ctrl-v: Paste +* Ctrl-h: Open help +* Ctrl-u: Half page up +* Ctrl-d: Half page down +* PageUp: Page up +* PageDown: Page down +* Ctrl-e: Execute a command + +You can also use the mouse to manipulate the text. Simply clicking and dragging will select text. You can also double click +to enable word selection, and triple click to enable line selection. + +# Configuration + +At this point, there isn't much you can configure. +Micro has a few options which you can set: + +* colorscheme +* tabsize +* syntax + +To set an option run Ctrl-e to execute a command, and type `set option value`, so to set the tabsize to 8 it would be `set tabsize 8`. + +Any option you set in the editor will be saved to the file `~/.micro/settings.json` so, in effect, your configuration file will be created +for you. If you'd like to take your configuration with you to another machine, simply copy the `settings.json` to the other machine. + +# Contributing + +If you find any bugs, please report them! I am also happy to accept pull requests from anyone. diff --git a/runtime/colorschemes/solarized-tc.micro b/runtime/colorschemes/solarized-tc.micro new file mode 100644 index 00000000..cbe58258 --- /dev/null +++ b/runtime/colorschemes/solarized-tc.micro @@ -0,0 +1,13 @@ +color-link default "#839496,#002833" +color-link comment "#586E75,#002833" +color-link identifier "#268BD2,#002833" +color-link constant "#2AA198,#002833" +color-link statement "#859900,#002833" +color-link prepreoc "#CB4B16,#002833" +color-link type "#B58900,#002833" +color-link special "#DC322F,#002833" +color-link underlined "#D33682,#002833" +color-link error "bold #CB4B16,#002833" +color-link todo "bold #D33682,#002833" +color-link statusline "#003541,#839496" +color-link line-numer "#586E75,#003541" diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 00000000..22f39dae Binary files /dev/null and b/screenshot.png differ diff --git a/src/buffer.go b/src/buffer.go index 0f91cf95..66b02afd 100644 --- a/src/buffer.go +++ b/src/buffer.go @@ -29,7 +29,7 @@ type Buffer struct { // Syntax highlighting rules rules []SyntaxRule - // File type of the buffer + // The buffer's filetype filetype string } diff --git a/src/colorscheme.go b/src/colorscheme.go index 6b6e757e..450da387 100644 --- a/src/colorscheme.go +++ b/src/colorscheme.go @@ -83,7 +83,7 @@ func ParseColorscheme(text string) Colorscheme { // The 'extra' can be bold, reverse, or underline func StringToStyle(str string) tcell.Style { var fg string - var bg string + bg := "default" split := strings.Split(str, ",") if len(split) > 1 { fg, bg = split[0], split[1] diff --git a/src/help.go b/src/help.go index 27051986..b8efab9e 100644 --- a/src/help.go +++ b/src/help.go @@ -16,6 +16,8 @@ Ctrl-o: Open file Ctrl-z: Undo Ctrl-y: Redo +Ctrl-f: Find + Ctrl-a: Select all Ctrl-c: Copy @@ -35,6 +37,11 @@ Possible commands: 'quit': Quits micro 'save': saves the current buffer + +'replace "search" "value"': This will replace 'search' with 'value'. +Note that 'search' must be a valid regex. If one of the arguments +does not have any spaces in it, you may omit the quotes. + 'set option value': sets the option to value. Please see the next section for a list of options you can set Micro options: @@ -66,7 +73,7 @@ func DisplayHelp() { lines := totalLines[topline:lineEnd] for y, line := range lines { for x, ch := range line { - st := tcell.StyleDefault + st := defStyle screen.SetContent(x, y, ch, nil, st) } } diff --git a/src/highlighter.go b/src/highlighter.go index 64787aaa..00f8b5a2 100644 --- a/src/highlighter.go +++ b/src/highlighter.go @@ -156,7 +156,7 @@ func LoadSyntaxFile(filename string) { // The user could give us a "color" that is really a part of the colorscheme // in which case we should look that up in the colorscheme // They can also just give us a straight up color - st := tcell.StyleDefault + st := defStyle if _, ok := colorscheme[color]; ok { st = colorscheme[color] } else { @@ -201,7 +201,7 @@ func LoadSyntaxFile(filename string) { // The user could give us a "color" that is really a part of the colorscheme // in which case we should look that up in the colorscheme // They can also just give us a straight up color - st := tcell.StyleDefault + st := defStyle if _, ok := colorscheme[color]; ok { st = colorscheme[color] } else { diff --git a/src/messenger.go b/src/messenger.go index df9f3f21..bb30ba2f 100644 --- a/src/messenger.go +++ b/src/messenger.go @@ -50,7 +50,7 @@ type Messenger struct { // Message sends a message to the user func (m *Messenger) Message(msg string) { m.message = msg - m.style = tcell.StyleDefault + m.style = defStyle if _, ok := colorscheme["message"]; ok { m.style = colorscheme["message"] @@ -61,7 +61,7 @@ func (m *Messenger) Message(msg string) { // Error sends an error message to the user func (m *Messenger) Error(msg string) { m.message = msg - m.style = tcell.StyleDefault. + m.style = defStyle. Foreground(tcell.ColorBlack). Background(tcell.ColorMaroon) @@ -172,7 +172,7 @@ func (m *Messenger) Reset() { func (m *Messenger) Clear() { w, h := screen.Size() for x := 0; x < w; x++ { - screen.SetContent(x, h-1, ' ', nil, tcell.StyleDefault) + screen.SetContent(x, h-1, ' ', nil, defStyle) } } diff --git a/src/micro.go b/src/micro.go index 89025981..33cf6777 100644 --- a/src/micro.go +++ b/src/micro.go @@ -23,8 +23,11 @@ var ( // Object to send messages and prompts to the user messenger *Messenger - redrawStatus int - searching bool + // Is there currently a search in progress + searching bool + + // The default style + defStyle tcell.Style ) // LoadInput loads the file input for the editor @@ -72,6 +75,9 @@ func main() { InitSettings() + // Load the syntax files, including the colorscheme + LoadSyntaxFiles() + // Should we enable true color? truecolor := os.Getenv("MICRO_TRUECOLOR") == "1" @@ -82,9 +88,6 @@ func main() { os.Setenv("TERM", "xterm-truecolor") } - // Load the syntax files, including the colorscheme - LoadSyntaxFiles() - // Initilize tcell screen, err = tcell.NewScreen() if err != nil { @@ -114,7 +117,7 @@ func main() { }() // Default style - defStyle := tcell.StyleDefault. + defStyle = tcell.StyleDefault. Foreground(tcell.ColorDefault). Background(tcell.ColorDefault) diff --git a/src/statusline.go b/src/statusline.go index a62b046a..f02d499f 100644 --- a/src/statusline.go +++ b/src/statusline.go @@ -1,7 +1,6 @@ package main import ( - "github.com/gdamore/tcell" "strconv" ) @@ -43,7 +42,7 @@ func (sline *Statusline) Display() { centerText := "Press Ctrl-h for help" - statusLineStyle := tcell.StyleDefault.Reverse(true) + statusLineStyle := defStyle.Reverse(true) if style, ok := colorscheme["statusline"]; ok { statusLineStyle = style } diff --git a/src/view.go b/src/view.go index dfc1a31a..51a433d3 100644 --- a/src/view.go +++ b/src/view.go @@ -10,8 +10,8 @@ import ( ) // The View struct stores information about a view into a buffer. -// It has a value for the cursor, and the window that the user sees -// the buffer from. +// It has a stores information about the cursor, and the viewport +// that the user sees the buffer from. type View struct { cursor Cursor @@ -356,18 +356,26 @@ func (v *View) HandleEvent(event tcell.Event) { switch e.Key() { case tcell.KeyUp: // Cursor up + v.cursor.ResetSelection() v.cursor.Up() case tcell.KeyDown: // Cursor down + v.cursor.ResetSelection() v.cursor.Down() case tcell.KeyLeft: // Cursor left + v.cursor.ResetSelection() v.cursor.Left() case tcell.KeyRight: // Cursor right + v.cursor.ResetSelection() v.cursor.Right() case tcell.KeyEnter: // Insert a newline + if v.cursor.HasSelection() { + v.cursor.DeleteSelection() + v.cursor.ResetSelection() + } v.eh.Insert(v.cursor.Loc(), "\n") v.cursor.Right() // Rehighlight the entire buffer @@ -376,6 +384,10 @@ func (v *View) HandleEvent(event tcell.Event) { // v.UpdateLines(v.cursor.y-1, v.cursor.y) case tcell.KeySpace: // Insert a space + if v.cursor.HasSelection() { + v.cursor.DeleteSelection() + v.cursor.ResetSelection() + } v.eh.Insert(v.cursor.Loc(), " ") v.cursor.Right() v.UpdateLines(v.cursor.y, v.cursor.y) @@ -405,6 +417,10 @@ func (v *View) HandleEvent(event tcell.Event) { v.cursor.lastVisualX = v.cursor.GetVisualX() case tcell.KeyTab: // Insert a tab + if v.cursor.HasSelection() { + v.cursor.DeleteSelection() + v.cursor.ResetSelection() + } v.eh.Insert(v.cursor.Loc(), "\t") v.cursor.Right() v.UpdateLines(v.cursor.y, v.cursor.y) @@ -600,7 +616,7 @@ func (v *View) DisplayView() { line := v.buf.lines[lineN+v.topline] // Write the line number - lineNumStyle := tcell.StyleDefault + lineNumStyle := defStyle if style, ok := colorscheme["line-number"]; ok { lineNumStyle = style } @@ -637,14 +653,14 @@ func (v *View) DisplayView() { // } else if lineN < len(v.lastMatches) && colN < len(v.lastMatches[lineN]) { // highlightStyle = v.lastMatches[lineN][colN] // } else { - // highlightStyle = tcell.StyleDefault + // highlightStyle = defStyle // } if v.cursor.HasSelection() && (charNum >= v.cursor.curSelection[0] && charNum < v.cursor.curSelection[1] || charNum < v.cursor.curSelection[0] && charNum >= v.cursor.curSelection[1]) { - lineStyle = tcell.StyleDefault.Reverse(true) + lineStyle = defStyle.Reverse(true) if style, ok := colorscheme["selection"]; ok { lineStyle = style @@ -679,7 +695,7 @@ func (v *View) DisplayView() { (charNum >= v.cursor.curSelection[0] && charNum < v.cursor.curSelection[1] || charNum < v.cursor.curSelection[0] && charNum >= v.cursor.curSelection[1]) { - selectStyle := tcell.StyleDefault.Reverse(true) + selectStyle := defStyle.Reverse(true) if style, ok := colorscheme["selection"]; ok { selectStyle = style diff --git a/todolist.md b/todolist.md index ce1daa32..6c824d97 100644 --- a/todolist.md +++ b/todolist.md @@ -10,16 +10,16 @@ - [ ] Horizontal splits - [ ] Vertical splits -- [ ] More keybindings - - [x] Page up and page down - - [x] CtrlA for select all - - [x] CtrlO for open file - - [ ] CtrlF for find - - [x] CtrlZ for undo - - [x] CtrlY for redo - - [ ] Custom bindings +- [ ] Persistent undo/redo (saved between open and closing micro) + +- [ ] Auto indent + +- [ ] More options + - [ ] Tabs to spaces + - [ ] Wrap lines + ### Done - [x] Line numbers @@ -34,6 +34,9 @@ - [x] Proper error handling +- [x] Syntax highlighting + - [x] Use nano-like syntax files (https://github.com/scopatz/nanorc) + - [x] Cleanup - [x] Unicode support @@ -42,6 +45,14 @@ - [x] Allow executing simple commands at the bottom of the editor (like vim or emacs) +- [x] More keybindings + - [x] Page up and page down + - [x] CtrlA for select all + - [x] CtrlO for open file + - [x] CtrlF for find + - [x] CtrlZ for undo + - [x] CtrlY for redo + - [x] Help screen - [x] Help screen which lists keybindings and commands - [x] Opened with Ctrl-h @@ -54,15 +65,9 @@ - [x] Saved between sessions - [x] Colorscheme - [x] tab size - - [ ] tabs or spaces - -- [x] Syntax highlighting - - [x] Use nano-like syntax files (https://github.com/scopatz/nanorc) - - [ ] Optimization - [x] Undo/redo - [x] Undo/redo stack - - [ ] Persistent undo/redo (saved between open and closing micro) - [x] Clipboard support - [x] Paste