mirror of
https://github.com/EnumeratedDev/Typer.git
synced 2025-07-01 23:58:22 +00:00
Compare commits
3 Commits
cd823c9d9f
...
cc3b4ecf18
Author | SHA1 | Date | |
---|---|---|---|
cc3b4ecf18 | |||
1b6b45aaea | |||
e2ac216d6e |
@ -5,4 +5,5 @@ selected_style_fallback: "default-fallback" # Style for 8-color capable terminal
|
||||
# Other
|
||||
show_top_menu: true
|
||||
show_line_index: true
|
||||
buffer_info_message: "File: %f Cursor: (%x, %y, %p) Chars: %c"
|
||||
tab_indentation: 4 # Length of tab characters
|
@ -8,22 +8,24 @@ import (
|
||||
)
|
||||
|
||||
type TyperConfig struct {
|
||||
SelectedStyle string `yaml:"selected_style,omitempty"`
|
||||
FallbackStyle string `yaml:"fallback_style,omitempty"`
|
||||
ShowTopMenu bool `yaml:"show_top_menu,omitempty"`
|
||||
ShowLineIndex bool `yaml:"show_line_index,omitempty"`
|
||||
TabIndentation int `yaml:"tab_indentation,omitempty"`
|
||||
SelectedStyle string `yaml:"selected_style,omitempty"`
|
||||
FallbackStyle string `yaml:"fallback_style,omitempty"`
|
||||
ShowTopMenu bool `yaml:"show_top_menu,omitempty"`
|
||||
ShowLineIndex bool `yaml:"show_line_index,omitempty"`
|
||||
BufferInfoMessage string `yaml:"buffer_info_message,omitempty"`
|
||||
TabIndentation int `yaml:"tab_indentation,omitempty"`
|
||||
}
|
||||
|
||||
var Config TyperConfig
|
||||
|
||||
func readConfig() {
|
||||
Config = TyperConfig{
|
||||
SelectedStyle: "default",
|
||||
FallbackStyle: "default-fallback",
|
||||
ShowTopMenu: true,
|
||||
ShowLineIndex: true,
|
||||
TabIndentation: 4,
|
||||
SelectedStyle: "default",
|
||||
FallbackStyle: "default-fallback",
|
||||
ShowTopMenu: true,
|
||||
ShowLineIndex: true,
|
||||
BufferInfoMessage: "File: %f Cursor: (%x, %y, %p) Chars: %c",
|
||||
TabIndentation: 4,
|
||||
}
|
||||
|
||||
homeDir, err := os.UserHomeDir()
|
||||
|
@ -133,11 +133,38 @@ func drawTopMenu(window *Window) {
|
||||
}
|
||||
|
||||
// Draw buffer info
|
||||
bufferInfoMsg := getBufferInfoMsg(window)
|
||||
drawText(screen, sizeX-len(bufferInfoMsg)-1, 0, sizeX-1, 0, topMenuStyle, bufferInfoMsg)
|
||||
}
|
||||
|
||||
func getBufferInfoMsg(window *Window) string {
|
||||
pathToFile := "Not set"
|
||||
filename := "Not set"
|
||||
if window.CurrentBuffer.filename != "" {
|
||||
pathToFile = window.CurrentBuffer.filename
|
||||
}
|
||||
if filepath.Base(window.CurrentBuffer.filename) != "." {
|
||||
filename = filepath.Base(window.CurrentBuffer.filename)
|
||||
}
|
||||
|
||||
cursorPos := window.CurrentBuffer.CursorPos
|
||||
cursorX, cursorY := window.GetCursorPos2D()
|
||||
cursorInfo := fmt.Sprintf("File: %s Cursor: (%d,%d,%d) Words: %d", filename, cursorX+1, cursorY+1, window.CurrentBuffer.CursorPos+1, len(strings.Fields(window.CurrentBuffer.Contents)))
|
||||
drawText(screen, sizeX-len(cursorInfo)-1, 0, sizeX-1, 0, topMenuStyle, cursorInfo)
|
||||
cursorX++
|
||||
cursorY++
|
||||
|
||||
chars := len(window.CurrentBuffer.Contents)
|
||||
words := len(strings.Fields(window.CurrentBuffer.Contents))
|
||||
|
||||
ret := Config.BufferInfoMessage
|
||||
|
||||
ret = strings.ReplaceAll(ret, "\n", " ")
|
||||
ret = strings.ReplaceAll(ret, "%F", pathToFile)
|
||||
ret = strings.ReplaceAll(ret, "%f", filename)
|
||||
ret = strings.ReplaceAll(ret, "%x", strconv.Itoa(cursorX))
|
||||
ret = strings.ReplaceAll(ret, "%y", strconv.Itoa(cursorY))
|
||||
ret = strings.ReplaceAll(ret, "%p", strconv.Itoa(cursorPos))
|
||||
ret = strings.ReplaceAll(ret, "%c", strconv.Itoa(chars))
|
||||
ret = strings.ReplaceAll(ret, "%w", strconv.Itoa(words))
|
||||
|
||||
return ret
|
||||
}
|
||||
|
200
src/window.go
200
src/window.go
@ -5,6 +5,8 @@ import (
|
||||
"log"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type CursorMode uint8
|
||||
@ -36,6 +38,7 @@ type Window struct {
|
||||
}
|
||||
|
||||
var mouseHeld = false
|
||||
var lastClick int64 = 0
|
||||
|
||||
func CreateWindow() (*Window, error) {
|
||||
window := Window{
|
||||
@ -184,16 +187,47 @@ func (window *Window) Draw() {
|
||||
func (window *Window) input(ev *tcell.EventKey) {
|
||||
if ev.Key() == tcell.KeyRight { // Navigation Keys
|
||||
if window.CursorMode == CursorModeBuffer {
|
||||
// Get original cursor position
|
||||
pos := window.CurrentBuffer.CursorPos
|
||||
|
||||
if ev.Modifiers()&tcell.ModCtrl != 0 {
|
||||
// Move cursor to start of word
|
||||
// Set variable to one character right of current position
|
||||
endOfWord := pos + 1
|
||||
if endOfWord >= len(window.CurrentBuffer.Contents) {
|
||||
endOfWord = len(window.CurrentBuffer.Contents)
|
||||
}
|
||||
|
||||
// Skip all spaces
|
||||
for endOfWord < len(window.CurrentBuffer.Contents) && unicode.IsSpace(rune(window.CurrentBuffer.Contents[endOfWord])) {
|
||||
endOfWord++
|
||||
}
|
||||
|
||||
// Find end of word
|
||||
for endOfWord < len(window.CurrentBuffer.Contents) && !unicode.IsSpace(rune(window.CurrentBuffer.Contents[endOfWord])) {
|
||||
endOfWord++
|
||||
}
|
||||
|
||||
window.SetCursorPos(endOfWord)
|
||||
} else {
|
||||
// Move cursor one character backwards
|
||||
window.SetCursorPos(window.CurrentBuffer.CursorPos + 1)
|
||||
}
|
||||
|
||||
// Add to selection
|
||||
if ev.Modifiers() == tcell.ModShift {
|
||||
if ev.Modifiers()&tcell.ModShift != 0 {
|
||||
if window.CurrentBuffer.Selection == nil {
|
||||
// Cancel cursor movement when creating selection without holding ctrl
|
||||
if ev.Modifiers()&tcell.ModCtrl == 0 {
|
||||
window.SetCursorPos(pos)
|
||||
}
|
||||
|
||||
window.CurrentBuffer.Selection = &Selection{
|
||||
selectionStart: window.CurrentBuffer.CursorPos,
|
||||
selectionStart: pos,
|
||||
selectionEnd: window.CurrentBuffer.CursorPos,
|
||||
}
|
||||
return
|
||||
} else {
|
||||
window.CurrentBuffer.Selection.selectionEnd = window.CurrentBuffer.CursorPos + 1
|
||||
window.CurrentBuffer.Selection.selectionEnd = window.CurrentBuffer.CursorPos
|
||||
}
|
||||
// Prevent selecting dummy character at the end of the buffer
|
||||
if window.CurrentBuffer.Selection.selectionEnd >= len(window.CurrentBuffer.Contents) {
|
||||
@ -202,46 +236,83 @@ func (window *Window) input(ev *tcell.EventKey) {
|
||||
} else if window.CurrentBuffer.Selection != nil {
|
||||
// Unset selection
|
||||
window.CurrentBuffer.Selection = nil
|
||||
return
|
||||
}
|
||||
// Move cursor
|
||||
window.SetCursorPos(window.CurrentBuffer.CursorPos + 1)
|
||||
}
|
||||
} else if ev.Key() == tcell.KeyLeft {
|
||||
if window.CursorMode == CursorModeBuffer {
|
||||
// Get original cursor position
|
||||
pos := window.CurrentBuffer.CursorPos
|
||||
|
||||
if ev.Modifiers()&tcell.ModCtrl != 0 {
|
||||
// Move cursor to start of word
|
||||
// Set variable to one character left of current position
|
||||
startOfWord := pos - 1
|
||||
if startOfWord < 0 {
|
||||
startOfWord = 0
|
||||
}
|
||||
|
||||
// Skip all spaces
|
||||
for startOfWord >= 0 && len(window.CurrentBuffer.Contents) != 0 && unicode.IsSpace(rune(window.CurrentBuffer.Contents[startOfWord])) {
|
||||
startOfWord--
|
||||
}
|
||||
|
||||
// Find start of word
|
||||
for startOfWord >= 0 && len(window.CurrentBuffer.Contents) != 0 && !unicode.IsSpace(rune(window.CurrentBuffer.Contents[startOfWord])) {
|
||||
startOfWord--
|
||||
}
|
||||
|
||||
// Move one character to the right
|
||||
startOfWord++
|
||||
|
||||
window.SetCursorPos(startOfWord)
|
||||
} else {
|
||||
// Move cursor one character backwards
|
||||
window.SetCursorPos(window.CurrentBuffer.CursorPos - 1)
|
||||
}
|
||||
|
||||
// Add to selection
|
||||
if ev.Modifiers() == tcell.ModShift {
|
||||
if ev.Modifiers()&tcell.ModShift != 0 {
|
||||
if window.CurrentBuffer.Selection == nil {
|
||||
// Cancel cursor movement when creating selection without holding ctrl
|
||||
if ev.Modifiers()&tcell.ModCtrl == 0 {
|
||||
window.SetCursorPos(pos)
|
||||
}
|
||||
|
||||
window.CurrentBuffer.Selection = &Selection{
|
||||
selectionStart: window.CurrentBuffer.CursorPos,
|
||||
selectionStart: pos,
|
||||
selectionEnd: window.CurrentBuffer.CursorPos,
|
||||
}
|
||||
return
|
||||
} else {
|
||||
window.CurrentBuffer.Selection.selectionEnd = window.CurrentBuffer.CursorPos - 1
|
||||
window.CurrentBuffer.Selection.selectionEnd = window.CurrentBuffer.CursorPos
|
||||
}
|
||||
} else if window.CurrentBuffer.Selection != nil {
|
||||
// Unset selection
|
||||
window.CurrentBuffer.Selection = nil
|
||||
return
|
||||
}
|
||||
// Move cursor
|
||||
window.SetCursorPos(window.CurrentBuffer.CursorPos - 1)
|
||||
}
|
||||
} else if ev.Key() == tcell.KeyUp {
|
||||
if window.CursorMode == CursorModeBuffer {
|
||||
// Get original cursor position
|
||||
pos := window.CurrentBuffer.CursorPos
|
||||
// Move cursor
|
||||
x, y := window.GetCursorPos2D()
|
||||
window.SetCursorPos2D(x, y-1)
|
||||
|
||||
if ev.Modifiers()&tcell.ModCtrl != 0 {
|
||||
// Move cursor to top of buffer
|
||||
window.SetCursorPos(0)
|
||||
} else {
|
||||
// Move cursor one line up
|
||||
x, y := window.GetCursorPos2D()
|
||||
window.SetCursorPos2D(x, y-1)
|
||||
}
|
||||
|
||||
// Add to selection
|
||||
if ev.Modifiers() == tcell.ModShift {
|
||||
if ev.Modifiers()&tcell.ModShift != 0 {
|
||||
// Add to selection
|
||||
if window.CurrentBuffer.Selection == nil {
|
||||
window.CurrentBuffer.Selection = &Selection{
|
||||
selectionStart: window.CurrentBuffer.CursorPos,
|
||||
selectionEnd: pos,
|
||||
selectionStart: pos,
|
||||
selectionEnd: window.CurrentBuffer.CursorPos,
|
||||
}
|
||||
} else {
|
||||
window.CurrentBuffer.Selection.selectionEnd = window.CurrentBuffer.CursorPos
|
||||
@ -276,11 +347,18 @@ func (window *Window) input(ev *tcell.EventKey) {
|
||||
if window.CursorMode == CursorModeBuffer {
|
||||
// Get original cursor position
|
||||
pos := window.CurrentBuffer.CursorPos
|
||||
// Move cursor
|
||||
x, y := window.GetCursorPos2D()
|
||||
window.SetCursorPos2D(x, y+1)
|
||||
|
||||
if ev.Modifiers()&tcell.ModCtrl != 0 {
|
||||
// Move cursor to bottom of buffer
|
||||
window.SetCursorPos(len(window.CurrentBuffer.Contents))
|
||||
} else {
|
||||
// Move cursor one line down
|
||||
x, y := window.GetCursorPos2D()
|
||||
window.SetCursorPos2D(x, y+1)
|
||||
}
|
||||
|
||||
// Add to selection
|
||||
if ev.Modifiers() == tcell.ModShift {
|
||||
if ev.Modifiers()&tcell.ModShift != 0 {
|
||||
// Add to selection
|
||||
if window.CurrentBuffer.Selection == nil {
|
||||
window.CurrentBuffer.Selection = &Selection{
|
||||
@ -484,9 +562,12 @@ func (window *Window) mouseInput(ev *tcell.EventMouse) {
|
||||
|
||||
// Left click was pressed
|
||||
if ev.Buttons() == tcell.Button1 {
|
||||
// Get last click time
|
||||
lastClickTime := time.UnixMilli(lastClick)
|
||||
// Ensure click was in buffer area
|
||||
x1, y1, x2, y2 := window.GetTextAreaDimensions()
|
||||
if mouseX >= x1 && mouseY >= y1 && mouseX <= x2 && mouseY <= y2 {
|
||||
currentX, currentY := window.GetCursorPos2D()
|
||||
bufferMouseX, bufferMouseY := window.AbsolutePosToCursorPos2D(mouseX, mouseY)
|
||||
if mouseHeld {
|
||||
// Add to selection
|
||||
@ -495,6 +576,10 @@ func (window *Window) mouseInput(ev *tcell.EventMouse) {
|
||||
selectionStart: window.CurrentBuffer.CursorPos,
|
||||
selectionEnd: window.CursorPos2DToCursorPos(bufferMouseX, bufferMouseY),
|
||||
}
|
||||
|
||||
// Set last click time
|
||||
lastClick = time.Now().UnixMilli()
|
||||
|
||||
return
|
||||
} else {
|
||||
window.CurrentBuffer.Selection.selectionEnd = window.CursorPos2DToCursorPos(bufferMouseX, bufferMouseY)
|
||||
@ -503,6 +588,74 @@ func (window *Window) mouseInput(ev *tcell.EventMouse) {
|
||||
if window.CurrentBuffer.Selection.selectionEnd >= len(window.CurrentBuffer.Contents) {
|
||||
window.CurrentBuffer.Selection.selectionEnd = len(window.CurrentBuffer.Contents) - 1
|
||||
}
|
||||
} else if currentX == bufferMouseX && currentY == bufferMouseY && window.CurrentBuffer.CursorPos < len(window.CurrentBuffer.Contents) && time.Since(lastClickTime).Milliseconds() < 300 {
|
||||
selectedText := window.CurrentBuffer.GetSelectedText()
|
||||
if window.CurrentBuffer.Selection == nil || strings.HasSuffix(selectedText, "\n") {
|
||||
// Select word
|
||||
startOfWord := window.CurrentBuffer.CursorPos
|
||||
endOfWord := window.CurrentBuffer.CursorPos
|
||||
|
||||
// Find end of word
|
||||
for i := window.CurrentBuffer.CursorPos + 1; i < len(window.CurrentBuffer.Contents); i++ {
|
||||
currentRune := rune(window.CurrentBuffer.Contents[i])
|
||||
if unicode.IsLetter(currentRune) || unicode.IsDigit(currentRune) || currentRune == '_' {
|
||||
endOfWord++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Find start of word
|
||||
for i := window.CurrentBuffer.CursorPos - 1; i >= 0; i-- {
|
||||
currentRune := rune(window.CurrentBuffer.Contents[i])
|
||||
if unicode.IsLetter(currentRune) || unicode.IsDigit(currentRune) || currentRune == '_' {
|
||||
startOfWord--
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Add to selection
|
||||
window.CurrentBuffer.Selection = &Selection{
|
||||
selectionStart: startOfWord,
|
||||
selectionEnd: endOfWord,
|
||||
}
|
||||
} else {
|
||||
// Select line
|
||||
startOfLine := window.CurrentBuffer.CursorPos
|
||||
endOfLine := window.CurrentBuffer.CursorPos
|
||||
|
||||
// Find end of line
|
||||
for i := window.CurrentBuffer.CursorPos + 1; i < len(window.CurrentBuffer.Contents); i++ {
|
||||
currentLetter := window.CurrentBuffer.Contents[i]
|
||||
|
||||
endOfLine++
|
||||
if currentLetter == '\n' {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Find start of line
|
||||
for i := window.CurrentBuffer.CursorPos - 1; i >= 0; i-- {
|
||||
currentLetter := window.CurrentBuffer.Contents[i]
|
||||
if currentLetter != '\n' {
|
||||
startOfLine--
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Add to selection
|
||||
window.CurrentBuffer.Selection = &Selection{
|
||||
selectionStart: startOfLine,
|
||||
selectionEnd: endOfLine,
|
||||
}
|
||||
}
|
||||
|
||||
// Set last click time
|
||||
lastClick = time.Now().UnixMilli()
|
||||
|
||||
return
|
||||
} else {
|
||||
// Clear selection
|
||||
if window.CurrentBuffer.Selection != nil {
|
||||
@ -511,6 +664,9 @@ func (window *Window) mouseInput(ev *tcell.EventMouse) {
|
||||
}
|
||||
// Move cursor
|
||||
window.SetCursorPos2D(bufferMouseX, bufferMouseY)
|
||||
|
||||
// Set last click time
|
||||
lastClick = time.Now().UnixMilli()
|
||||
}
|
||||
mouseHeld = true
|
||||
} else if ev.Buttons() == tcell.ButtonNone {
|
||||
|
Loading…
x
Reference in New Issue
Block a user