-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit fc3f711
Showing
21 changed files
with
1,954 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2016 Dave MacFarlane | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# The de Editor | ||
|
||
de is a programmer's editor, where that programmer happens to be [driusan](https://github.com/driusan/). | ||
|
||
It's kind of like a bastard child of vim and Plan 9's ACME editor, because vim feels inadequate on a | ||
computer with a mouse after using acme, and acme feels inadequate on a computer with a keyboard after | ||
using vi. | ||
|
||
Like vim, it's a modal editor with syntax highlighting that uses hjkl for movement. | ||
Like acme, it attempts to exploit your current environment instead of replacing it and tries to | ||
make the mouse useful. | ||
|
||
See [USAGE.md](USAGE.md) for usage instructions. | ||
|
||
## Features | ||
|
||
* Syntax highlighting (currently Go only) | ||
* vi-like keybindings and philosophy | ||
* acme-like mouse bindings and philosophy | ||
|
||
|
||
## Limitations and Bugs | ||
|
||
* vi-like functionality not fully implemented (most notably repeating a command by prefixing it | ||
with a number, and some movement verbs like '%' are missing.) | ||
* Can not open multiple files/windows at a time. (if your workflow is like mine, it means you often | ||
save and quit, do something in the shell, and then relaunch your editor. The startup time should | ||
be fast enough to support this style of workflow.) | ||
* Missing acme style window tag to use as a scratch space. | ||
|
||
# Installation | ||
|
||
It should be installable with the standard go tools: | ||
|
||
``` | ||
go get github.com/driusan/de | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# de Usage Instructions | ||
|
||
## Basic Usage | ||
de is a modal editor that starts in normal mode. The three modes currently implemented are | ||
Normal (biege background), Insert (light green background), and Delete mode (light red/pink | ||
background). The keybindings are inspired by, but not identical to, vi. | ||
|
||
In Normal and Delete modes, the movement commands are similar to vi. hjkl move the cursor. | ||
Shift-6 (^) moves the cursor to the start of the line, and Shift-4 ($) moves the cursor to the | ||
end of the line, G moves to end of file (or a line number if you type the line number before hitting | ||
G). w moves the cursor to the next word. In Delete mode it will delete from the current cursor up | ||
to that point, and in Normal mode it will either move to, or select up to that point depending on if | ||
the ctrl key is pressed. Other movement commands will be implemented, but that's all I've done up to now. | ||
Unlike in vi, the h and l keys do not stop at line boundaries. p will insert the most recently | ||
delete text, replacing the currently selected text. | ||
|
||
Generally, when I find myself typing a keystroke out of muscle-memory enough times as a long | ||
time vi-user, I implement it, or a close enough approximation to it, here. Ranges with a repeat | ||
(ie 3dw) are not yet implemented, but will be eventually. | ||
|
||
In Normal mode you can enter Insert mode by pressing 'i' or Delete mode by pressing 'd' and | ||
the background colour should change to indicate the current mode. | ||
|
||
In Insert mode, the arrow keys take on the same meaning as hjkl in Normal mode, and Escape will | ||
return to normal mode. Any other key combination that results in a printable unicode character | ||
being sent to de will insert the utf8 encoding of that character at the current location of the | ||
file. In all other modes, the arrow keys scroll the viewport without adjusting the cursor. | ||
|
||
In all modes, backspace will delete the currently selected text (or previous character if nothing | ||
is selected) without changing the mode. | ||
|
||
Pressing the Escape key will save the current file and exit. *NOTE TO VI USERS: RE-READ THE LAST | ||
SENTENCE* | ||
|
||
## Mouse Usage | ||
|
||
While the keyboard usage is inspired by vim, the mouse usage is inspired by acme. | ||
The mouse works the same way regardless of keyboard mode. | ||
|
||
Clicking anywhere with the left mouse button will move the text cursor or select text. | ||
|
||
Clicking with the right mouse button will search for the next instance of the word clicked on | ||
and select the next instance found. If the word is a filename, changes to the current file will be | ||
discarded and the clicked file will be opened in the current window. The keyboard equivalent | ||
for the currently selected text is the slash key (although slash will not open a file.) | ||
|
||
Clicking with the middle mouse button will "execute" the word clicked on. (see below.) | ||
|
||
Chording will probably eventually work similarly to acme, but isn't yet implemented. | ||
|
||
## Executing Words | ||
|
||
Words that are selected or clicked on can be "executed" to control the editor, either by | ||
selecting the word and then pressing the Enter key, or by clicking with the middle mouse button. | ||
(When executing with the keyboard, it will first check if the file exists and open it if applicable, | ||
similarly to searching with the mouse.) | ||
|
||
If executing a point in a word instead of a selection, that word will be executed. | ||
|
||
If the word is an internal editor command, it will perform that command. Otherwise, the shell command | ||
will be executed and the output will replace the currently selected text. | ||
|
||
Currently understood commands: | ||
Get (or Discard): Reload the current file from disk and discard changes | ||
Put (or Save): Save the current character buffer to disk, overwriting the existing file. | ||
Exit (or Quit): Quit de, discarding any changes. | ||
|
||
To be implemented: | ||
Copy (or Snarf), Cut, Paste, | ||
ACME style tag/Scratch line |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package actions | ||
|
||
import ( | ||
"github.com/driusan/de/demodel" | ||
) | ||
|
||
func DeleteCursor(From, To demodel.Position, buff *demodel.CharBuffer) { | ||
if buff == nil { | ||
return | ||
} | ||
|
||
dot := demodel.Dot{} | ||
i, err := From(*buff) | ||
if err != nil { | ||
return | ||
} | ||
dot.Start = i | ||
|
||
i, err = To(*buff) | ||
if err != nil { | ||
return | ||
} | ||
dot.End = i | ||
if dot.Start == dot.End { | ||
// nothing selected, so delete the previous character | ||
|
||
if dot.Start == 0 { | ||
// can't delete past the beginning | ||
return | ||
} | ||
|
||
buff.Buffer = append( | ||
buff.Buffer[:dot.Start-1], buff.Buffer[dot.Start:]..., | ||
) | ||
|
||
// now adjust dot if it was inside the deleted range.. | ||
if buff.Dot.Start == dot.Start { | ||
buff.Dot.Start -= 1 | ||
buff.Dot.End = buff.Dot.Start | ||
} | ||
return | ||
} else { | ||
// delete the selected text. | ||
buff.SnarfBuffer = make([]byte, dot.End-dot.Start) | ||
copy(buff.SnarfBuffer, buff.Buffer[dot.Start:dot.End]) | ||
|
||
buff.Buffer = append(buff.Buffer[:dot.Start], buff.Buffer[dot.End:]...) | ||
|
||
// now adjust dot if it was inside the deleted range.. | ||
if buff.Dot.Start >= dot.Start && buff.Dot.End <= dot.End { | ||
buff.Dot.Start = dot.Start | ||
buff.Dot.End = buff.Dot.Start | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package actions | ||
|
||
import ( | ||
"fmt" | ||
"github.com/driusan/de/demodel" | ||
"io/ioutil" | ||
"os" | ||
"os/exec" | ||
) | ||
|
||
func PerformAction(From, To demodel.Position, buff *demodel.CharBuffer) { | ||
if buff == nil { | ||
return | ||
} | ||
|
||
dot := demodel.Dot{} | ||
i, err := From(*buff) | ||
if err != nil { | ||
return | ||
} | ||
|
||
dot.Start = i | ||
i, err = To(*buff) | ||
if err != nil { | ||
return | ||
} | ||
dot.End = i | ||
|
||
cmd := string(buff.Buffer[dot.Start : dot.End+1]) | ||
runOrExec(cmd, buff) | ||
} | ||
|
||
func OpenOrPerformAction(From, To demodel.Position, buff *demodel.CharBuffer) { | ||
if buff == nil { | ||
return | ||
} | ||
|
||
dot := demodel.Dot{} | ||
i, err := From(*buff) | ||
if err != nil { | ||
return | ||
} | ||
|
||
dot.Start = i | ||
i, err = To(*buff) | ||
if err != nil { | ||
return | ||
} | ||
dot.End = i | ||
|
||
var cmd string | ||
if dot.End+1 >= uint(len(buff.Buffer)) { | ||
cmd = string(buff.Buffer[dot.Start:]) | ||
} else { | ||
cmd = string(buff.Buffer[dot.Start : dot.End+1]) | ||
} | ||
|
||
if _, err := os.Stat(cmd); err == nil { | ||
// the file exists, so open it | ||
b, ferr := ioutil.ReadFile(cmd) | ||
if ferr != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", err) | ||
return | ||
} | ||
buff.Buffer = b | ||
buff.Filename = cmd | ||
buff.Dot.Start = 0 | ||
buff.Dot.End = 0 | ||
return | ||
} | ||
runOrExec(cmd, buff) | ||
} | ||
|
||
func runOrExec(cmd string, buff *demodel.CharBuffer) { | ||
|
||
if f, ok := actions[cmd]; ok { | ||
// it was an internal command, so run it. | ||
f("", buff) | ||
return | ||
} | ||
|
||
// it wasn't an internal command, so run the shell command | ||
gocmd := exec.Command(cmd) | ||
stdout, err := gocmd.StdoutPipe() | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", err) | ||
return | ||
} | ||
if err := gocmd.Start(); err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", err) | ||
return | ||
} | ||
output, err := ioutil.ReadAll(stdout) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", err) | ||
return | ||
} | ||
if err := gocmd.Wait(); err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", err) | ||
} | ||
// nothing selected, so insert at dot.Start | ||
newBuffer := make([]byte, len(buff.Buffer)-int((buff.Dot.End-buff.Dot.Start))+len(output)) | ||
copy(newBuffer, buff.Buffer) | ||
copy(newBuffer[buff.Dot.Start:], output) | ||
copy(newBuffer[int(buff.Dot.Start)+len(output):], buff.Buffer[buff.Dot.End:]) | ||
|
||
buff.Buffer = newBuffer | ||
|
||
fmt.Printf("Output: %s\n", string(output)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package actions | ||
|
||
import ( | ||
"fmt" | ||
"github.com/driusan/de/demodel" | ||
"io/ioutil" | ||
"os" | ||
) | ||
|
||
// Changes Dot to next instance of the character sequence between From | ||
// and To | ||
func FindNext(From, To demodel.Position, buff *demodel.CharBuffer) { | ||
if buff == nil { | ||
return | ||
} | ||
dot := demodel.Dot{} | ||
i, err := From(*buff) | ||
if err != nil { | ||
return | ||
} | ||
dot.Start = i | ||
|
||
i, err = To(*buff) | ||
if err != nil { | ||
return | ||
} | ||
dot.End = i + 1 | ||
|
||
word := string(buff.Buffer[dot.Start:dot.End]) | ||
lenword := dot.End - dot.Start | ||
for i := dot.End; i < uint(len(buff.Buffer))-lenword; i++ { | ||
if string(buff.Buffer[i:i+lenword]) == word { | ||
buff.Dot.Start = i | ||
buff.Dot.End = i + lenword - 1 | ||
return | ||
} | ||
} | ||
|
||
} | ||
|
||
func FindNextOrOpen(From, To demodel.Position, buff *demodel.CharBuffer) { | ||
if buff == nil { | ||
return | ||
} | ||
dot := demodel.Dot{} | ||
i, err := From(*buff) | ||
if err != nil { | ||
return | ||
} | ||
dot.Start = i | ||
|
||
i, err = To(*buff) | ||
if err != nil { | ||
return | ||
} | ||
dot.End = i + 1 | ||
|
||
word := string(buff.Buffer[dot.Start:dot.End]) | ||
|
||
fmt.Printf("Word: %s\n", word) | ||
if _, err := os.Stat(word); err == nil { | ||
// the file exists, so open it | ||
b, ferr := ioutil.ReadFile(word) | ||
if ferr != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", err) | ||
return | ||
} | ||
buff.Buffer = b | ||
buff.Filename = word | ||
buff.Dot.Start = 0 | ||
buff.Dot.End = 0 | ||
return | ||
} | ||
|
||
// the file doesn't exist, so find the next instance of word. | ||
lenword := dot.End - dot.Start | ||
for i := dot.End; i < uint(len(buff.Buffer))-lenword; i++ { | ||
if string(buff.Buffer[i:i+lenword]) == word { | ||
buff.Dot.Start = i | ||
buff.Dot.End = i + lenword - 1 | ||
return | ||
} | ||
} | ||
} |
Oops, something went wrong.