Merge branch 'master' of github.com:roodletoof/dotfiles

This commit is contained in:
Ivar Fatland
2026-05-12 17:36:21 +02:00
5 changed files with 226 additions and 162 deletions
+14
View File
@@ -612,6 +612,20 @@ require'lazy'.setup{ --{{{1
}, },
}, },
}, },
{ "seblyng/roslyn.nvim", --{{{2
opts = {
---function to pick which .sln file to use when opening a cs file
---@param targets string[]
choose_target=function (targets)
if targets == nil then return end
if #targets == 0 then return end
table.sort(targets, function(a, b)
return #a < #b
end)
return targets[1]
end
},
},
{ 'neovim/nvim-lspconfig', --{{{2 { 'neovim/nvim-lspconfig', --{{{2
dependencies = { dependencies = {
'williamboman/mason.nvim', 'williamboman/mason.nvim',
+1 -1
View File
@@ -1,4 +1,4 @@
module github.com/roodletoof/raymenu module github.com/roodletoof/dotfiles/raymenu
go 1.26.2 go 1.26.2
+5 -161
View File
@@ -8,24 +8,9 @@ import (
"slices" "slices"
"strings" "strings"
_ "embed" "github.com/roodletoof/dotfiles/raymenu/picker"
rg "github.com/gen2brain/raylib-go/raygui"
rl "github.com/gen2brain/raylib-go/raylib"
"github.com/ktr0731/go-fuzzyfinder/matching"
) )
const fontSize = 20
const textBoxHeight = fontSize + 6
// TODO: move the raymenu function to its own package
//go:embed gomono-font/Go-Mono.ttf
var font_tff []byte
type State struct {
Font rl.Font
}
func main() { func main() {
input, err := io.ReadAll(os.Stdin) input, err := io.ReadAll(os.Stdin)
@@ -36,153 +21,12 @@ func main() {
choices = slices.DeleteFunc(choices, func(l string) bool { choices = slices.DeleteFunc(choices, func(l string) bool {
return l == "" return l == ""
}) })
choice, ok := raymenu(choices) choice, ok := picker.Picker(
choices,
)
if ok { if ok {
fmt.Println(choice) fmt.Println(choices[choice])
} }
} }
func isPressedRepeat(key int32) bool {
return rl.IsKeyPressed(key) || rl.IsKeyPressedRepeat(key)
}
func raymenu(options []string) (choice string, ok bool) {
state := initialize(len(options))
rg.SetFont(state.Font)
rg.SetStyle(rg.DEFAULT, rg.TEXT_SIZE, fontSize)
// TODO kinda dumb with additional initialization here
originalOrder := make([]matching.Matched, len(options))
for i := range options {
originalOrder[i].Idx=i
}
cursor := 0
matched := originalOrder
var prevInput string
var input string
for !rl.WindowShouldClose() {
rl.BeginDrawing()
rl.ClearBackground(rl.Black)
if !rl.IsWindowFocused() {
return "", false
}
resetBounds()
bounds := nextBounds()
isControlDown := rl.IsKeyDown(rl.KeyLeftControl) || rl.IsKeyDown(rl.KeyRightControl)
alternativeBackspace := isPressedRepeat(rl.KeyH) && isControlDown
enter := (rl.IsKeyPressed(rl.KeyY) && isControlDown) ||
rl.IsKeyPressed(rl.KeyEnter)
if alternativeBackspace && len(input) > 0 {
input = input[:len(input)-1]
}
rg.TextBox(bounds, &input, 1024, true)
if prevInput != input {
if len(input) > 0 {
matched = matching.FindAll(input, options)
} else {
matched = originalOrder
}
cursor = 0
prevInput = input
}
{ // cursor update
moveCursorUp := isPressedRepeat(rl.KeyP) && isControlDown
moveCursorDown := isPressedRepeat(rl.KeyN) && isControlDown
if moveCursorUp {
cursor -= 1
}
if moveCursorDown {
cursor += 1
}
if cursor >= len(matched) {
cursor = len(matched) - 1
}
if cursor < 0 {
cursor = 0
}
}
if enter {
rl.CloseWindow()
if cursor < len(matched) {
return options[matched[cursor].Idx], true
}
return "", false
}
for i, match := range matched {
bounds := nextBounds()
textBounds := bounds
textBounds.X += textBounds.Height
textBounds.Width -= textBounds.Height
rg.DrawText(
options[match.Idx],
textBounds,
int32(rg.TEXT_ALIGN_LEFT),
rl.White,
)
if i == cursor {
// TODO if cursor is not visible then keep some offset or make
// 2d camera so you can scroll through all the options if you
// want
rl.DrawCircle(
int32(bounds.X)+int32(bounds.Height)/2,
int32(bounds.Y)+int32(bounds.Height)/2,
max(textBoxHeight / 8, 1),
rl.White,
)
}
}
rl.EndDrawing()
}
return "", false
}
var yOffset float32 = 0.0
func resetBounds() {
yOffset = 0.0
}
func nextBounds() (bounds rl.Rectangle) {
bounds = rl.Rectangle{X: 0, Y: yOffset, Width: float32(rl.GetScreenWidth()), Height: textBoxHeight}
yOffset += textBoxHeight
return
}
func initialize(nOptions int) State {
rl.SetTraceLogLevel(rl.LogError)
rl.InitWindow(0, 0, "raymenu")
rl.SetWindowState(rl.FlagWindowUndecorated)
rl.SetTargetFPS(
int32(
rl.GetMonitorRefreshRate(
rl.GetCurrentMonitor(),
),
),
)
monitor := rl.GetCurrentMonitor()
monitorWidth := rl.GetMonitorWidth(monitor)
monitorHeight := rl.GetMonitorHeight(monitor)
rl.SetWindowSize(
monitorWidth/2,
min(monitorHeight/2/textBoxHeight, nOptions+1)*textBoxHeight,
)
rl.SetWindowPosition(
monitorWidth/2-rl.GetScreenWidth()/2,
monitorHeight/2-rl.GetScreenHeight()/2,
)
return State{
Font: rl.LoadFontFromMemory(".ttf", font_tff, fontSize, nil),
}
}
+206
View File
@@ -0,0 +1,206 @@
package picker
import (
rg "github.com/gen2brain/raylib-go/raygui"
rl "github.com/gen2brain/raylib-go/raylib"
"github.com/ktr0731/go-fuzzyfinder/matching"
_ "embed"
)
const fontSize = 20
const textBoxHeight = fontSize + 6
//go:embed gomono-font/Go-Mono.ttf
var font_tff []byte
func style() {
rg.SetFont(rl.LoadFontFromMemory(".ttf", font_tff, fontSize, nil))
rg.SetStyle(rg.DEFAULT, rg.TEXT_SIZE, fontSize)
rg.SetStyle(
rg.DEFAULT,
rg.BASE_COLOR_PRESSED,
rg.NewColorPropertyValue(rl.Black),
)
rg.SetStyle(
rg.DEFAULT,
rg.BORDER_COLOR_PRESSED,
rg.NewColorPropertyValue(rl.White),
)
rg.SetStyle(
rg.DEFAULT,
rg.TEXT_COLOR_PRESSED,
rg.NewColorPropertyValue(rl.White),
)
}
type RaylibPickerOptions struct {
Prompt string
}
var defaultPickerOptions = RaylibPickerOptions{}
type PickerOption func(*RaylibPickerOptions)
func WithPrompt(prompt string) PickerOption {
return func(opts *RaylibPickerOptions) {
opts.Prompt = prompt
}
}
func Picker(options []string, pickerOptions ...PickerOption) (choiceIdx int, ok bool) {
pickerOpts := defaultPickerOptions
for _, opt := range pickerOptions {
opt(&pickerOpts)
}
initialize(len(options))
// TODO kinda dumb with additional initialization here
originalOrder := make([]matching.Matched, len(options))
for i := range options {
originalOrder[i].Idx=i
}
cursor := 0
matched := originalOrder
var prevInput string
var input string
for !rl.WindowShouldClose() {
rl.BeginDrawing()
rl.ClearBackground(rl.Black)
if !rl.IsWindowFocused() {
return 0, false
}
resetBounds()
bounds := nextBounds()
isControlDown := rl.IsKeyDown(rl.KeyLeftControl) || rl.IsKeyDown(rl.KeyRightControl)
alternativeBackspace := isPressedRepeat(rl.KeyH) && isControlDown
enter := (rl.IsKeyPressed(rl.KeyY) && isControlDown) ||
rl.IsKeyPressed(rl.KeyEnter)
if alternativeBackspace && len(input) > 0 {
input = input[:len(input)-1]
}
rg.TextBox(bounds, &input, 1024, true)
if input == "" {
promptBounds := bounds
promptBounds.X += promptBounds.Height
promptBounds.Width -= promptBounds.Height
rg.DrawText(
pickerOpts.Prompt,
promptBounds,
int32(rg.TEXT_ALIGN_LEFT),
rl.Gray,
)
}
if prevInput != input {
if len(input) > 0 {
matched = matching.FindAll(input, options)
} else {
matched = originalOrder
}
cursor = 0
prevInput = input
}
{ // cursor update
moveCursorUp := isPressedRepeat(rl.KeyP) && isControlDown
moveCursorDown := isPressedRepeat(rl.KeyN) && isControlDown
if moveCursorUp {
cursor -= 1
}
if moveCursorDown {
cursor += 1
}
if cursor >= len(matched) {
cursor = len(matched) - 1
}
if cursor < 0 {
cursor = 0
}
}
if enter {
rl.CloseWindow()
if cursor < len(matched) {
return matched[cursor].Idx, true
}
return 0, false
}
for i, match := range matched {
bounds := nextBounds()
textBounds := bounds
textBounds.X += textBounds.Height
textBounds.Width -= textBounds.Height
rg.DrawText(
options[match.Idx],
textBounds,
int32(rg.TEXT_ALIGN_LEFT),
rl.White,
)
if i == cursor {
// TODO if cursor is not visible then keep some offset or make
// 2d camera so you can scroll through all the options if you
// want
rl.DrawCircle(
int32(bounds.X)+int32(bounds.Height)/2,
int32(bounds.Y)+int32(bounds.Height)/2,
max(textBoxHeight / 8, 1),
rl.White,
)
}
}
rl.EndDrawing()
}
return 0, false
}
func initialize(nOptions int) {
rl.SetTraceLogLevel(rl.LogError)
rl.InitWindow(0, 0, "raymenu")
rl.SetWindowState(rl.FlagWindowUndecorated)
rl.SetTargetFPS(
int32(
rl.GetMonitorRefreshRate(
rl.GetCurrentMonitor(),
),
),
)
monitor := rl.GetCurrentMonitor()
monitorWidth := rl.GetMonitorWidth(monitor)
monitorHeight := rl.GetMonitorHeight(monitor)
rl.SetWindowSize(
monitorWidth/2,
min(monitorHeight/2/textBoxHeight, nOptions+1)*textBoxHeight,
)
rl.SetWindowPosition(
monitorWidth/2-rl.GetScreenWidth()/2,
monitorHeight/2-rl.GetScreenHeight()/2,
)
style()
}
func isPressedRepeat(key int32) bool {
return rl.IsKeyPressed(key) || rl.IsKeyPressedRepeat(key)
}
var yOffset float32 = 0.0
func resetBounds() {
yOffset = 0.0
}
func nextBounds() (bounds rl.Rectangle) {
bounds = rl.Rectangle{X: 0, Y: yOffset, Width: float32(rl.GetScreenWidth()), Height: textBoxHeight}
yOffset += textBoxHeight
return
}