mirror of
https://github.com/EnumeratedDev/typer.git
synced 2026-09-20 23:26:11 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee29fae6af
|
||
|
|
ae8e702a77
|
||
|
|
01bc6702a9
|
||
|
|
5af962c6b2
|
||
|
|
5b4723d7d4
|
||
|
|
cc92ba51c5
|
||
|
|
69178e42b1
|
@@ -6,5 +6,6 @@ selected_style_fallback: "default-fallback" # Style for 8-color capable terminal
|
||||
show_top_menu: true
|
||||
show_line_index: true
|
||||
extend_line_index: false # Extend line index to the bottom of the screen
|
||||
color_message_bar: true # Add color to message bar messages
|
||||
buffer_info_message: "File: %f, Filetype: %t, Cursor: (%x, %y, %p), Chars: %c"
|
||||
tab_indentation: 4 # Length of tab characters
|
||||
|
||||
+8
-10
@@ -604,7 +604,7 @@ func GetOpenFileBuffer(filename string) *Buffer {
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateFileBuffer(filename string, openNonExistentFile bool) (*Buffer, error) {
|
||||
func CreateFileBuffer(filename string) (*Buffer, error) {
|
||||
// Replace tilde with home directory
|
||||
if filename != "~" && strings.HasPrefix(filename, "~/") {
|
||||
homedir, err := os.UserHomeDir()
|
||||
@@ -623,22 +623,20 @@ func CreateFileBuffer(filename string, openNonExistentFile bool) (*Buffer, error
|
||||
}
|
||||
|
||||
stat, err := os.Stat(abs)
|
||||
if !openNonExistentFile {
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !stat.Mode().IsRegular() {
|
||||
return nil, fmt.Errorf("%s is not a regular file", filename)
|
||||
}
|
||||
} else if !stat.Mode().IsRegular() {
|
||||
return nil, fmt.Errorf("not a regular file")
|
||||
}
|
||||
|
||||
if GetBufferByName(filename) != nil {
|
||||
return nil, fmt.Errorf("a buffer with the name (%s) is already open", filename)
|
||||
return nil, fmt.Errorf("a buffer with the same name is already open")
|
||||
}
|
||||
|
||||
if GetBufferByFilename(abs) != nil {
|
||||
return nil, fmt.Errorf("%s is already open in another buffer", filename)
|
||||
return nil, fmt.Errorf("file is already open in another buffer")
|
||||
}
|
||||
|
||||
buffer := Buffer{
|
||||
@@ -675,7 +673,7 @@ func CreateBuffer(bufferName string) (*Buffer, error) {
|
||||
}
|
||||
|
||||
if GetBufferByName(bufferName) != nil {
|
||||
return nil, fmt.Errorf("a buffer with the name (%s) is already open", bufferName)
|
||||
return nil, fmt.Errorf("a buffer with the same name is already open")
|
||||
}
|
||||
|
||||
Buffers = append(Buffers, &buffer)
|
||||
|
||||
+2
-2
@@ -141,9 +141,9 @@ func initCommands() {
|
||||
window.PrintMessage(fmt.Sprintf("File already open! Switching to buffer: %s", openBuffer.Name), TYPER_MESSAGE_INFO)
|
||||
window.CurrentBuffer = openBuffer
|
||||
} else {
|
||||
newBuffer, err := CreateFileBuffer(input, false)
|
||||
newBuffer, err := CreateFileBuffer(input)
|
||||
if err != nil {
|
||||
window.PrintMessage(fmt.Sprintf("Could not open file: %s", err.Error()), TYPER_MESSAGE_WARNING)
|
||||
window.PrintMessage(fmt.Sprintf("Could not open file %s: %s", input, err), TYPER_MESSAGE_ERROR)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ type TyperConfig struct {
|
||||
FallbackStyle string `yaml:"fallback_style,omitempty"`
|
||||
ShowTopMenu bool `yaml:"show_top_menu,omitempty"`
|
||||
ShowLineIndex bool `yaml:"show_line_index,omitempty"`
|
||||
ColorMessageBar bool `yaml:"color_message_bar"`
|
||||
ExtendLineIndex bool `yaml:"extend_line_index,omitempty"`
|
||||
BufferInfoMessage string `yaml:"buffer_info_message,omitempty"`
|
||||
TabIndentation int `yaml:"tab_indentation,omitempty"`
|
||||
|
||||
+24
-16
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
@@ -34,29 +35,36 @@ func main() {
|
||||
log.Fatalf("Failed to create window: %v", err)
|
||||
}
|
||||
|
||||
if flag.NArg() > 0 {
|
||||
for i, file := range flag.Args() {
|
||||
b, err := CreateFileBuffer(file, true)
|
||||
if err != nil {
|
||||
window.PrintMessage("Could not open file: "+file, TYPER_MESSAGE_ERROR)
|
||||
continue
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
window.CurrentBuffer = b
|
||||
Buffers = Buffers[1:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create logs buffer
|
||||
logsBuffer, err := CreateBuffer("Logs")
|
||||
logsBuffer, err := CreateBuffer("Typer Logs")
|
||||
if err != nil {
|
||||
log.Fatalf("Could not create logs buffer")
|
||||
}
|
||||
logsBuffer.filetype = "typer_logs"
|
||||
logsBuffer.canEdit = false
|
||||
|
||||
// Open paths passed as arguments
|
||||
if flag.NArg() > 0 {
|
||||
for _, file := range flag.Args() {
|
||||
buffer, err := CreateFileBuffer(file)
|
||||
if err != nil {
|
||||
window.PrintMessage(fmt.Sprintf("Could not open file %s: %s", file, err), TYPER_MESSAGE_ERROR)
|
||||
continue
|
||||
}
|
||||
|
||||
if window.CurrentBuffer == nil {
|
||||
window.CurrentBuffer = buffer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if window.CurrentBuffer == nil {
|
||||
buffer, err := CreateBuffer("New Buffer 1")
|
||||
if err == nil {
|
||||
window.CurrentBuffer = buffer
|
||||
}
|
||||
}
|
||||
|
||||
for !window.closed {
|
||||
window.Draw()
|
||||
window.ProcessEvents()
|
||||
|
||||
+10
-1
@@ -27,7 +27,7 @@ var lastMessage *TyperMessage
|
||||
func (window *Window) PrintMessage(message string, urgency TyperMessageUrgency) {
|
||||
lastMessage = &TyperMessage{Timestamp: time.Now().UnixMilli(), Message: message, Urgency: urgency}
|
||||
|
||||
logsBuffer := GetBufferByName("Logs")
|
||||
logsBuffer := GetBufferByName("Typer Logs")
|
||||
if logsBuffer != nil {
|
||||
messageToPrint := ""
|
||||
switch lastMessage.Urgency {
|
||||
@@ -82,10 +82,19 @@ func drawMessageBar(window *Window) {
|
||||
if lastMessage != nil && time.Since(time.UnixMilli(lastMessage.Timestamp)).Seconds() < 5 {
|
||||
switch lastMessage.Urgency {
|
||||
case TYPER_MESSAGE_INFO:
|
||||
if Config.ColorMessageBar {
|
||||
messageBarStyle = messageBarStyle.Foreground(CurrentStyle.SyntaxInfo)
|
||||
}
|
||||
messageToPrint = "[INFO] "
|
||||
case TYPER_MESSAGE_WARNING:
|
||||
if Config.ColorMessageBar {
|
||||
messageBarStyle = messageBarStyle.Foreground(CurrentStyle.SyntaxWarning)
|
||||
}
|
||||
messageToPrint = "[WARNING] "
|
||||
case TYPER_MESSAGE_ERROR:
|
||||
if Config.ColorMessageBar {
|
||||
messageBarStyle = messageBarStyle.Foreground(CurrentStyle.SyntaxError)
|
||||
}
|
||||
messageToPrint = "[ERROR] "
|
||||
default:
|
||||
messageToPrint = "[???] "
|
||||
|
||||
+24
-6
@@ -5,6 +5,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"typer/runestring"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
@@ -85,9 +86,11 @@ func initTopMenu() {
|
||||
}
|
||||
|
||||
buffersSlice := make([]string, 0)
|
||||
selected := 0
|
||||
for i, buffer := range Buffers {
|
||||
if window.CurrentBuffer == buffer {
|
||||
buffersSlice = append(buffersSlice, fmt.Sprintf("[%d] * %s", i+1, buffer.Name))
|
||||
selected = i
|
||||
} else {
|
||||
buffersSlice = append(buffersSlice, fmt.Sprintf("[%d] %s", i+1, buffer.Name))
|
||||
}
|
||||
@@ -99,6 +102,7 @@ func initTopMenu() {
|
||||
ClearDropdowns()
|
||||
window.CursorMode = CursorModeBuffer
|
||||
})
|
||||
d.Selected = selected
|
||||
ActiveDropdown = d
|
||||
window.CursorMode = CursorModeDropdown
|
||||
},
|
||||
@@ -148,9 +152,7 @@ func getBufferInfoMsg(window *Window) string {
|
||||
filetype = window.CurrentBuffer.filetype
|
||||
}
|
||||
|
||||
contents := window.CurrentBuffer.GetContentsAsString()
|
||||
chars := len(contents)
|
||||
words := len(strings.Fields(string(contents)))
|
||||
var contents runestring.RuneString = nil
|
||||
|
||||
ret := Config.BufferInfoMessage
|
||||
|
||||
@@ -160,9 +162,25 @@ func getBufferInfoMsg(window *Window) string {
|
||||
ret = strings.ReplaceAll(ret, "%t", filetype)
|
||||
ret = strings.ReplaceAll(ret, "%x", strconv.Itoa(window.CurrentBuffer.CursorPos.X+1))
|
||||
ret = strings.ReplaceAll(ret, "%y", strconv.Itoa(window.CurrentBuffer.CursorPos.Y+1))
|
||||
ret = strings.ReplaceAll(ret, "%p", strconv.Itoa(window.CurrentBuffer.PositionToAbsolutePosition(window.CurrentBuffer.CursorPos)+1))
|
||||
ret = strings.ReplaceAll(ret, "%c", strconv.Itoa(chars))
|
||||
ret = strings.ReplaceAll(ret, "%w", strconv.Itoa(words))
|
||||
|
||||
// Only replace if found for expensive calls
|
||||
if strings.Contains(ret, "%p") {
|
||||
ret = strings.ReplaceAll(ret, "%p", strconv.Itoa(window.CurrentBuffer.PositionToAbsolutePosition(window.CurrentBuffer.CursorPos)+1))
|
||||
}
|
||||
if strings.Contains(ret, "%c") {
|
||||
contents = window.CurrentBuffer.GetContentsAsString()
|
||||
|
||||
chars := len(contents)
|
||||
ret = strings.ReplaceAll(ret, "%c", strconv.Itoa(chars))
|
||||
}
|
||||
if strings.Contains(ret, "%w") {
|
||||
if contents == nil {
|
||||
contents = window.CurrentBuffer.GetContentsAsString()
|
||||
}
|
||||
|
||||
words := len(strings.Fields(string(contents)))
|
||||
ret = strings.ReplaceAll(ret, "%w", strconv.Itoa(words))
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
+1
-2
@@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
@@ -23,7 +22,7 @@ func GetConfigPath(relativeConfigPath string) string {
|
||||
|
||||
paths := make([]string, 0)
|
||||
if *configDirFlag != "" {
|
||||
paths = append(paths, path.Join(*configDirFlag, relativeConfigPath))
|
||||
paths = append(paths, filepath.Join(*configDirFlag, relativeConfigPath))
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
|
||||
+33
-11
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"typer/runestring"
|
||||
@@ -57,14 +56,6 @@ func CreateWindow() (*Window, error) {
|
||||
screen: nil,
|
||||
}
|
||||
|
||||
// Create empty buffer if nil
|
||||
for i := 1; window.CurrentBuffer == nil; i++ {
|
||||
buffer, err := CreateBuffer("New Buffer " + strconv.Itoa(i))
|
||||
if err == nil {
|
||||
window.CurrentBuffer = buffer
|
||||
}
|
||||
}
|
||||
|
||||
// Create tcell screen
|
||||
screen, err := tcell.NewScreen()
|
||||
if err != nil {
|
||||
@@ -491,9 +482,40 @@ func (window *Window) handleMouseInput(ev *tcell.EventMouse) {
|
||||
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 {
|
||||
|
||||
if mouseY == 0 && Config.ShowTopMenu && !mouseHeld {
|
||||
// Mouse is in top menu
|
||||
|
||||
// Find clicked button
|
||||
buttonFound := false
|
||||
for _, button := range TopMenuButtons {
|
||||
if mouseX >= button.PosX && mouseX <= button.PosX+len(button.Name) {
|
||||
buttonFound = true
|
||||
button.Action(window, &button)
|
||||
}
|
||||
}
|
||||
|
||||
if !buttonFound {
|
||||
// Exit top menu
|
||||
ClearDropdowns()
|
||||
window.CursorMode = CursorModeBuffer
|
||||
}
|
||||
} else if window.CursorMode == CursorModeDropdown && !mouseHeld {
|
||||
// Mouse is in top menu
|
||||
|
||||
if mouseX >= ActiveDropdown.PosX && mouseX <= ActiveDropdown.PosX+ActiveDropdown.Width+1 && mouseY > ActiveDropdown.PosY && mouseY <= ActiveDropdown.PosY+len(ActiveDropdown.Options) {
|
||||
// Dropdown button clicked
|
||||
ActiveDropdown.Selected = mouseY - ActiveDropdown.PosY - 1
|
||||
ActiveDropdown.Action(ActiveDropdown.Selected)
|
||||
} else {
|
||||
// Exit top menu
|
||||
ClearDropdowns()
|
||||
window.CursorMode = CursorModeBuffer
|
||||
}
|
||||
} else if mouseX >= x1 && mouseY >= y1 && mouseX <= x2 && mouseY <= y2 && window.CursorMode == CursorModeBuffer {
|
||||
// Mouse is in buffer area
|
||||
currentPos := window.CurrentBuffer.CursorPos
|
||||
mouseBufferPos := Position{mouseX + window.CurrentBuffer.Offset.X - x1, mouseY + window.CurrentBuffer.Offset.Y - y1}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user