got backspace and enter working
parent
cab3304e5b
commit
def28180f2
18
file.go
18
file.go
|
|
@ -29,9 +29,9 @@ func fileOpen(fname string) {
|
|||
state.rows = append(state.rows, fread.Text())
|
||||
}
|
||||
|
||||
// if len(state.rows) == 0 || (len(state.rows) == 1 && state.rows[0] == "") {
|
||||
// state.rows = []string{" "}
|
||||
// }
|
||||
if len(state.rows) == 0 || (len(state.rows) == 1 && state.rows[0] == "") {
|
||||
state.rows = []string{""}
|
||||
}
|
||||
}
|
||||
|
||||
f.Close()
|
||||
|
|
@ -47,14 +47,24 @@ func fileSave() {
|
|||
defer f.Close()
|
||||
|
||||
bytesWritten := 0
|
||||
charsWritten := 0
|
||||
linesWritten := 0
|
||||
for _, row := range state.rows {
|
||||
bw, err := fmt.Fprintf(f, "%s\n", row)
|
||||
if err != nil {
|
||||
log.Fatalf("COULD NOT SAVE FILE: %v", err)
|
||||
}
|
||||
bytesWritten += bw
|
||||
charsWritten += len([]rune(row)) + 1
|
||||
linesWritten++
|
||||
}
|
||||
|
||||
state.StatusLine = fmt.Sprintf("'%s' wrote %d bytes.", state.file, bytesWritten)
|
||||
state.StatusLines[1] = fmt.Sprintf(
|
||||
"'%s' saved. %dL, %dC, %d bytes",
|
||||
state.file,
|
||||
linesWritten,
|
||||
charsWritten,
|
||||
bytesWritten,
|
||||
)
|
||||
|
||||
}
|
||||
|
|
|
|||
144
input.go
144
input.go
|
|
@ -33,9 +33,7 @@ const (
|
|||
|
||||
func editorKeyPresses() bool {
|
||||
char := editorReadKey()
|
||||
state.StatusLine = ""
|
||||
|
||||
editorMoveCaret(char)
|
||||
state.StatusLines[1] = ""
|
||||
|
||||
if char == ctrl_key('r') {
|
||||
uiRefresh()
|
||||
|
|
@ -55,71 +53,133 @@ func editorKeyPresses() bool {
|
|||
editorRemoveChar(char)
|
||||
} else if char >= 32 && char <= 126 || char == KEY_ENTER || char == KEY_TAB {
|
||||
editorInsertChar(char)
|
||||
} else {
|
||||
editorMoveCaret(char)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func editorRemoveChar(char rune) {
|
||||
lineText := state.rows[state.Cy]
|
||||
rl := state.getCurrentRowLen()
|
||||
|
||||
cx := state.Cx
|
||||
cy := state.Cy
|
||||
rc := len(state.rows)
|
||||
|
||||
lt := ""
|
||||
rl := 0
|
||||
|
||||
if rc > 0 {
|
||||
lt = state.rows[cy]
|
||||
rl = state.getCurrentRowLen()
|
||||
}
|
||||
|
||||
// file is empty
|
||||
if rc == 0 && lt == "" {
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
1. Backspace at beginning of a line
|
||||
2. Backspace in middle of a line
|
||||
3. Backspace at end of a line
|
||||
4. Backspace when there are 0 characters in the file
|
||||
*/
|
||||
if char == KEY_BACKSPACE {
|
||||
if cx == 0 && state.Cy > 0 {
|
||||
plt := state.rows[state.Cy-1]
|
||||
state.rows[state.Cy-1] = fmt.Sprintf("%s%s", plt, lineText)
|
||||
if state.Cy < len(state.rows)-1 {
|
||||
state.rows = append(state.rows[:state.Cy-1], state.rows[state.Cy:]...)
|
||||
editorMoveCaret(KEY_UP_ARROW)
|
||||
} else {
|
||||
state.rows = state.rows[:state.Cy-1]
|
||||
state.Cy--
|
||||
}
|
||||
state.Cx = 0
|
||||
} else if cx == 0 {
|
||||
// do nothing because there are no characters
|
||||
if cx == 0 && cy == 0 {
|
||||
return
|
||||
} else {
|
||||
state.StatusLine = fmt.Sprintf("D: %d - %s%s", cx, lineText[:cx-1], lineText[cx:])
|
||||
state.rows[state.Cy] = fmt.Sprintf("%s%s", lineText[:cx-1], lineText[cx:])
|
||||
}
|
||||
// backspace in the middle of a line
|
||||
if cx > 0 && cx < rl {
|
||||
state.rows[cy] = fmt.Sprintf("%s%s", lt[:cx-1], lt[cx:])
|
||||
editorMoveCaret(KEY_LEFT_ARROW)
|
||||
return
|
||||
}
|
||||
|
||||
// backspace at start of line
|
||||
// join lines together and remove
|
||||
if cx == 0 && cy > 0 {
|
||||
plt := state.rows[cy-1]
|
||||
_, highlightedRowLen := renderLine(plt)
|
||||
state.rows[cy-1] = fmt.Sprintf("%s%s", plt, lt)
|
||||
|
||||
editorMoveCaret(KEY_UP_ARROW)
|
||||
for x := 0; x < highlightedRowLen; x++ {
|
||||
editorMoveCaret(KEY_RIGHT_ARROW)
|
||||
}
|
||||
|
||||
// if we're at the last row, make sure to only remove the last line
|
||||
if cy == rc-1 {
|
||||
state.rows = state.rows[:cy]
|
||||
} else {
|
||||
state.rows = append(state.rows[:cy], state.rows[cy+1:]...)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// backspace at end of line
|
||||
if cx == rl {
|
||||
state.rows[cy] = lt[:cx-1]
|
||||
editorMoveCaret(KEY_LEFT_ARROW)
|
||||
return
|
||||
}
|
||||
|
||||
} else if char == KEY_DELETE {
|
||||
// in middle of line
|
||||
if cx < rl-1 {
|
||||
state.rows[state.Cy] = fmt.Sprintf("%s%s", lineText[:cx], lineText[cx+1:])
|
||||
state.rows[state.Cy] = fmt.Sprintf("%s%s", lt[:cx], lt[cx+1:])
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func editorInsertChar(char rune) {
|
||||
lt := ""
|
||||
cx := state.Cx
|
||||
if len(state.rows) > 0 {
|
||||
lt = state.rows[state.Cy]
|
||||
} else {
|
||||
state.rows = []string{fmt.Sprintf("%c", char)}
|
||||
return
|
||||
cy := state.Cy
|
||||
rc := len(state.rows)
|
||||
|
||||
lt := ""
|
||||
rl := 0
|
||||
|
||||
if rc > 0 {
|
||||
lt = state.rows[cy]
|
||||
rl = state.getCurrentRowLen()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
1. Enter at beginning line
|
||||
2. Enter at middle of line
|
||||
3. Enter at end of line
|
||||
*/
|
||||
if char == KEY_ENTER {
|
||||
oldL := lt[:cx]
|
||||
newL := lt[cx:]
|
||||
state.rows[state.Cy] = oldL
|
||||
if state.Cy == len(state.rows)-1 {
|
||||
state.rows[state.Cy] = oldL
|
||||
state.rows = append(state.rows, newL)
|
||||
} else {
|
||||
state.rows = append(append(state.rows[:state.Cy], newL), state.rows[state.Cy:]...)
|
||||
// beginning of line
|
||||
if cx == 0 {
|
||||
if cy == rc {
|
||||
state.rows = append(state.rows, lt)
|
||||
} else if cy < rc {
|
||||
state.rows = append(append(state.rows[:cy], lt), state.rows[cy:]...)
|
||||
}
|
||||
state.rows[cy] = ""
|
||||
|
||||
// end of a line
|
||||
} else if cx >= rl {
|
||||
if cy < rc {
|
||||
state.rows = append(append(state.rows[:cy], ""), state.rows[cy:]...)
|
||||
state.rows[cy] = lt
|
||||
} else if cy == rc {
|
||||
state.rows = append(state.rows[:cy], "")
|
||||
}
|
||||
// mid line
|
||||
} else if cx > 0 {
|
||||
state.rows = append(append(state.rows[:cy], lt[cx:]), state.rows[cy:]...)
|
||||
state.rows[cy] = lt[:cx]
|
||||
}
|
||||
|
||||
state.Cx = 0
|
||||
editorMoveCaret(KEY_DOWN_ARROW)
|
||||
} else {
|
||||
state.rows[state.Cy] = fmt.Sprintf("%s%c%s", lt[:cx], char, lt[cx:])
|
||||
state.StatusLines[1] = fmt.Sprintf("%c %d", char, char)
|
||||
state.rows[cy] = fmt.Sprintf("%s%c%s", lt[:cx], char, lt[cx:])
|
||||
editorMoveCaret(KEY_RIGHT_ARROW)
|
||||
}
|
||||
}
|
||||
|
|
@ -165,6 +225,8 @@ func editorMoveCaret(char rune) {
|
|||
case KEY_END:
|
||||
x = state.Cols - 1
|
||||
break
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
if char == ctrl_key(KEY_DOWN_ARROW) {
|
||||
|
|
|
|||
3
main.go
3
main.go
|
|
@ -19,7 +19,7 @@ type editorState struct {
|
|||
Cy int
|
||||
Rows int
|
||||
Cols int
|
||||
StatusLine string
|
||||
StatusLines [2]string
|
||||
DebugLine string
|
||||
rows []string
|
||||
rowOffset int
|
||||
|
|
@ -66,6 +66,7 @@ func initEditor() {
|
|||
state.Buffer = &bytes.Buffer{}
|
||||
state.rows = []string{fmt.Sprintf("Pound Ed %s", Version)}
|
||||
state.file = ""
|
||||
state.StatusLines = [2]string{}
|
||||
}
|
||||
|
||||
func cleanup() {
|
||||
|
|
|
|||
41
ui.go
41
ui.go
|
|
@ -16,8 +16,11 @@ import (
|
|||
const (
|
||||
CLEAR = "\x1b[K"
|
||||
TAB_SIZE = 8
|
||||
EMPTY_LINE_GUTTER = " x~ "
|
||||
EMPTY_LINE_GUTTER = " ~ "
|
||||
LINE_GUTTER = " "
|
||||
STATUSLINEHEIGHT = 2
|
||||
WHITESPACE = "\xB8"
|
||||
NEWLINE = '\xAC'
|
||||
)
|
||||
|
||||
func uiDrawRows() {
|
||||
|
|
@ -36,26 +39,22 @@ func uiDrawRows() {
|
|||
file = "NO FILE"
|
||||
}
|
||||
|
||||
statusLine := fmt.Sprintf(
|
||||
"%s\x1b[1;7m '%s' \x1b[m L:%d/%d C:%d/%d | H:%d W: %d | %s",
|
||||
state.StatusLines[0] = fmt.Sprintf(
|
||||
"%s\x1b[1;7m '%s' \x1b[m L:%d/%d C:%d/%d | H:%d W: %d",
|
||||
CLEAR,
|
||||
file,
|
||||
state.Cy+1,
|
||||
len(state.rows),
|
||||
rx+1,
|
||||
highlightedRowLen,
|
||||
highlightedRowLen+1,
|
||||
state.Rows-1,
|
||||
state.Cols-gutterWidth-1,
|
||||
state.StatusLine)
|
||||
state.Cols-gutterWidth-1)
|
||||
|
||||
|
||||
for y := 0; y < state.Rows; y++ {
|
||||
if y == state.Rows-1 {
|
||||
statusLen := len(statusLine)
|
||||
if statusLen > state.Cols {
|
||||
statusLen = state.Cols
|
||||
}
|
||||
buf.WriteString(statusLine[:statusLen])
|
||||
} else if y < state.Rows && state.Cy < len(state.rows) {
|
||||
if y >= state.Rows-STATUSLINEHEIGHT {
|
||||
buf.WriteString(drawStatusLine(y - (state.Rows - STATUSLINEHEIGHT)))
|
||||
} else if state.Cy < len(state.rows) && y + state.rowOffset < len(state.rows) {
|
||||
rowIdx := y + state.rowOffset
|
||||
|
||||
if rowIdx < len(state.rows) {
|
||||
|
|
@ -75,8 +74,8 @@ func uiDrawRows() {
|
|||
renderLen = rowEnd
|
||||
}
|
||||
|
||||
if state.colOffset < renderLen {
|
||||
buf.WriteString(row[state.colOffset:renderLen])
|
||||
if state.colOffset <= renderLen {
|
||||
buf.WriteString(fmt.Sprintf("%s%c", row[state.colOffset:renderLen], NEWLINE))
|
||||
}
|
||||
|
||||
if rowLen > rowEnd {
|
||||
|
|
@ -95,6 +94,16 @@ func uiDrawRows() {
|
|||
}
|
||||
}
|
||||
|
||||
func drawStatusLine(row int) string {
|
||||
statusLine := state.StatusLines[row]
|
||||
statusLen := len(statusLine)
|
||||
if statusLen > state.Cols {
|
||||
statusLen = state.Cols
|
||||
}
|
||||
return statusLine[:statusLen]
|
||||
}
|
||||
|
||||
|
||||
func uiRefresh() {
|
||||
buf := state.Buffer
|
||||
fmt.Fprintf(buf, "\x1b[?251")
|
||||
|
|
@ -222,7 +231,7 @@ func renderLine(line string) (string, int) {
|
|||
if char == '\t' {
|
||||
tabCount++
|
||||
for i := 0; i < TAB_SIZE; i++ {
|
||||
rl += " "
|
||||
rl += WHITESPACE
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue