fix: cleaned up and fixed the settings that needed updating

This commit is contained in:
Hayden Hargreaves 2026-03-05 14:34:21 -07:00
parent dc9a814508
commit 098641f5c0
10 changed files with 188 additions and 90 deletions

View File

@ -16,6 +16,7 @@ func main() {
win := core.NewWindowBuilder(). win := core.NewWindowBuilder().
WithBuffer(&buf). WithBuffer(&buf).
WithOptions(core.NewDefaultWinOptions()).
Build() Build()
model := editor.NewModelBuilder(). model := editor.NewModelBuilder().

View File

@ -241,7 +241,7 @@ func (a InsertTab) Execute(m Model) tea.Cmd {
x, y := win.Cursor.Col, win.Cursor.Line x, y := win.Cursor.Col, win.Cursor.Line
l := buf.Lines[y] l := buf.Lines[y]
tabs := strings.Repeat(" ", m.Settings().TabSize) tabs := strings.Repeat(" ", m.Settings().TabStop)
if x < len(l) { if x < len(l) {
buf.SetLine(y, l[:x]+tabs+l[x:]) buf.SetLine(y, l[:x]+tabs+l[x:])
} else { } else {

View File

@ -45,8 +45,8 @@ type Model interface {
Mode() core.Mode Mode() core.Mode
SetMode(mode core.Mode) SetMode(mode core.Mode)
Settings() core.Settings Settings() core.EditorSettings
SetSettings(s core.Settings) SetSettings(s core.EditorSettings)
// ================================================== // ==================================================
// Registers // Registers
@ -55,7 +55,6 @@ type Model interface {
GetRegister(name rune) (core.Register, bool) GetRegister(name rune) (core.Register, bool)
SetRegister(name rune, t core.RegisterType, cnt []string) error SetRegister(name rune, t core.RegisterType, cnt []string) error
UpdateDefaultRegister(t core.RegisterType, cnt []string) UpdateDefaultRegister(t core.RegisterType, cnt []string)
} }
// Action is the base interface - anything executable // Action is the base interface - anything executable

View File

@ -110,7 +110,15 @@ type Setting struct {
Name string Name string
ShortForm string ShortForm string
Type SettingType Type SettingType
Get func(s core.Settings) any Get func(s core.EditorSettings) any
Set func(m action.Model, val any)
}
type WindowSetting struct {
Name string
ShortForm string
Type SettingType
Get func(m action.Model) any
Set func(m action.Model, val any) Set func(m action.Model, val any)
} }
@ -123,50 +131,69 @@ const (
StringSetting StringSetting
) )
// settingsMap defines all available settings // settingsMap defines all available editor settings
var settingsMap = []Setting{ var settingsMap = []Setting{
{
Name: "tabstop",
ShortForm: "ts",
Type: IntSetting,
Get: func(s core.EditorSettings) any { return s.TabStop },
Set: func(m action.Model, val any) {
s := m.Settings()
s.TabStop = val.(int)
m.SetSettings(s)
},
},
}
// windowSettingsMap defines all available window settings
var windowSettingsMap = []WindowSetting{
{ {
Name: "number", Name: "number",
ShortForm: "nu", ShortForm: "nu",
Type: BoolSetting, Type: BoolSetting,
Get: func(s core.Settings) any { return s.Number }, Get: func(m action.Model) any { return m.ActiveWindow().Options.Number },
Set: func(m action.Model, val any) { Set: func(m action.Model, val any) {
s := m.Settings() w := m.ActiveWindow()
s.Number = val.(bool) o := w.Options
m.SetSettings(s) o.Number = val.(bool)
w.SetOptions(o)
}, },
}, },
{ {
Name: "relativenumber", Name: "relativenumber",
ShortForm: "rnu", ShortForm: "rnu",
Type: BoolSetting, Type: BoolSetting,
Get: func(s core.Settings) any { return s.RelativeNumber }, Get: func(m action.Model) any { return m.ActiveWindow().Options.RelativeNumber },
Set: func(m action.Model, val any) { Set: func(m action.Model, val any) {
s := m.Settings() w := m.ActiveWindow()
s.RelativeNumber = val.(bool) o := w.Options
m.SetSettings(s) o.RelativeNumber = val.(bool)
}, w.SetOptions(o)
},
{
Name: "tabstop",
ShortForm: "ts",
Type: IntSetting,
Get: func(s core.Settings) any { return s.TabSize },
Set: func(m action.Model, val any) {
s := m.Settings()
s.TabSize = val.(int)
m.SetSettings(s)
}, },
}, },
{ {
Name: "scrolloff", Name: "scrolloff",
ShortForm: "so", ShortForm: "so",
Type: IntSetting, Type: IntSetting,
Get: func(s core.Settings) any { return s.ScrollOff }, Get: func(m action.Model) any { return m.ActiveWindow().Options.ScrollOff },
Set: func(m action.Model, val any) { Set: func(m action.Model, val any) {
s := m.Settings() w := m.ActiveWindow()
s.ScrollOff = val.(int) o := w.Options
m.SetSettings(s) o.ScrollOff = val.(int)
w.SetOptions(o)
},
},
{
Name: "guttersize",
ShortForm: "gu",
Type: IntSetting,
Get: func(m action.Model) any { return m.ActiveWindow().Options.GutterSize },
Set: func(m action.Model, val any) {
w := m.ActiveWindow()
o := w.Options
o.GutterSize = val.(int)
w.SetOptions(o)
}, },
}, },
} }
@ -186,31 +213,66 @@ func lookupSetting(name string) *Setting {
return nil return nil
} }
// lookupWindowSetting: Finds a window setting by name, short form, or prefix.
func lookupWindowSetting(name string) *WindowSetting {
for i := range windowSettingsMap {
s := &windowSettingsMap[i]
if name == s.Name || name == s.ShortForm {
return s
}
// Prefix matching
if len(name) >= len(s.ShortForm) && strings.HasPrefix(s.Name, name) {
return s
}
}
return nil
}
// parseSetOption: Parses and applies a single :set option. // parseSetOption: Parses and applies a single :set option.
func parseSetOption(m action.Model, opt string) error { func parseSetOption(m action.Model, opt string) error {
// Handle toggle: option! // Handle toggle: option!
if name, ok := strings.CutSuffix(opt, "!"); ok { if name, ok := strings.CutSuffix(opt, "!"); ok {
setting := lookupSetting(name) setting := lookupSetting(name)
if setting == nil { if setting != nil {
return nil // Unknown setting if setting.Type == BoolSetting {
// Toggle the boolean
currentVal := setting.Get(m.Settings()).(bool)
setting.Set(m, !currentVal)
}
return nil
} }
if setting.Type == BoolSetting {
// Toggle the boolean windowSetting := lookupWindowSetting(name)
currentVal := setting.Get(m.Settings()).(bool) if windowSetting != nil {
setting.Set(m, !currentVal) if windowSetting.Type == BoolSetting {
// Toggle the boolean
currentVal := windowSetting.Get(m).(bool)
windowSetting.Set(m, !currentVal)
}
return nil
} }
return nil return nil
} }
// Handle disable: nooption // Handle disable: nooption
if name, ok := strings.CutPrefix(opt, "no"); ok { if name, ok := strings.CutPrefix(opt, "no"); ok {
setting := lookupSetting(name) setting := lookupSetting(name)
if setting == nil { if setting != nil {
if setting.Type == BoolSetting {
setting.Set(m, false)
}
return nil return nil
} }
if setting.Type == BoolSetting {
setting.Set(m, false) windowSetting := lookupWindowSetting(name)
if windowSetting != nil {
if windowSetting.Type == BoolSetting {
windowSetting.Set(m, false)
}
return nil
} }
return nil return nil
} }
@ -218,34 +280,63 @@ func parseSetOption(m action.Model, opt string) error {
if strings.Contains(opt, "=") { if strings.Contains(opt, "=") {
parts := strings.SplitN(opt, "=", 2) parts := strings.SplitN(opt, "=", 2)
name, value := parts[0], parts[1] name, value := parts[0], parts[1]
setting := lookupSetting(name) setting := lookupSetting(name)
if setting == nil { if setting != nil {
switch setting.Type {
case IntSetting:
intVal, err := strconv.Atoi(value)
if err != nil {
return err
}
setting.Set(m, intVal)
case StringSetting:
setting.Set(m, value)
case BoolSetting:
// Handle :set option=true / :set option=false
boolVal := value == "true" || value == "1" || value == "yes"
setting.Set(m, boolVal)
}
return nil return nil
} }
switch setting.Type {
case IntSetting: windowSetting := lookupWindowSetting(name)
intVal, err := strconv.Atoi(value) if windowSetting != nil {
if err != nil { switch windowSetting.Type {
return err case IntSetting:
intVal, err := strconv.Atoi(value)
if err != nil {
return err
}
windowSetting.Set(m, intVal)
case StringSetting:
windowSetting.Set(m, value)
case BoolSetting:
// Handle :set option=true / :set option=false
boolVal := value == "true" || value == "1" || value == "yes"
windowSetting.Set(m, boolVal)
} }
setting.Set(m, intVal) return nil
case StringSetting:
setting.Set(m, value)
case BoolSetting:
// Handle :set option=true / :set option=false
boolVal := value == "true" || value == "1" || value == "yes"
setting.Set(m, boolVal)
} }
return nil return nil
} }
// Handle enable: option (boolean only) // Handle enable: option (boolean only)
setting := lookupSetting(opt) setting := lookupSetting(opt)
if setting == nil { if setting != nil {
if setting.Type == BoolSetting {
setting.Set(m, true)
}
return nil return nil
} }
if setting.Type == BoolSetting {
setting.Set(m, true) windowSetting := lookupWindowSetting(opt)
if windowSetting != nil {
if windowSetting.Type == BoolSetting {
windowSetting.Set(m, true)
}
return nil
} }
return nil return nil

View File

@ -1,23 +1,15 @@
package core package core
// Settings: Configuration options for editor display and behavior. // EditorSettings: Configuration options for editor display and behavior.
type Settings struct { type EditorSettings struct {
Number bool TabStop int
RelativeNumber bool
GutterSize int
TabSize int
ScrollOff int
// TODO: Colors // TODO: Colors
} }
// NewDefaultSettings: Creates a Settings struct with sensible defaults for // NewDefaultSettings: Creates a Settings struct with sensible defaults for
// line numbers, gutter width, tab size, and scroll offset. // line numbers, gutter width, tab size, and scroll offset.
func NewDefaultSettings() Settings { func NewDefaultSettings() EditorSettings {
return Settings{ return EditorSettings{
Number: true, TabStop: 2,
RelativeNumber: true,
GutterSize: 5,
TabSize: 2,
ScrollOff: 8,
} }
} }

View File

@ -2,12 +2,22 @@ package core
// TODO: No more global settings, window-wide settings // TODO: No more global settings, window-wide settings
type WinOptions struct { type WinOptions struct {
// Number bool Number bool
RelativeNumber bool
GutterSize int
// Wrap bool // Wrap bool
// Relnumber bool
ScrollOff int ScrollOff int
} }
func NewDefaultWinOptions() WinOptions {
return WinOptions{
Number: true,
RelativeNumber: true,
GutterSize: 5,
ScrollOff: 8,
}
}
type Window struct { type Window struct {
Id int Id int
Number int // Ignored for now, will be used when splits come into play Number int // Ignored for now, will be used when splits come into play
@ -181,3 +191,8 @@ func (w *Window) SetDimensions(width, height int) {
w.Width = width w.Width = width
w.Height = height w.Height = height
} }
// Window.SetOptions: Sets the options of this window.
func (w *Window) SetOptions(opts WinOptions) {
w.Options = opts
}

View File

@ -102,8 +102,8 @@ func TestCommandSetInteger(t *testing.T) {
sendKeys(tm, ":", "s", "e", "t", " ", "t", "a", "b", "s", "t", "o", "p", "=", "4", "enter") sendKeys(tm, ":", "s", "e", "t", " ", "t", "a", "b", "s", "t", "o", "p", "=", "4", "enter")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Settings().TabSize != 4 { if m.Settings().TabStop != 4 {
t.Errorf("TabSize = %d, want 4", m.Settings().TabSize) t.Errorf("TabSize = %d, want 4", m.Settings().TabStop)
} }
}) })
@ -114,8 +114,8 @@ func TestCommandSetInteger(t *testing.T) {
sendKeys(tm, ":", "s", "e", "t", " ", "t", "s", "=", "8", "enter") sendKeys(tm, ":", "s", "e", "t", " ", "t", "s", "=", "8", "enter")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Settings().TabSize != 8 { if m.Settings().TabStop != 8 {
t.Errorf("TabSize = %d, want 8", m.Settings().TabSize) t.Errorf("TabSize = %d, want 8", m.Settings().TabStop)
} }
}) })

View File

@ -42,7 +42,7 @@ type Model struct {
commandOutput string commandOutput string
// Global settings (TODO: This needs to be refactored) // Global settings (TODO: This needs to be refactored)
settings core.Settings settings core.EditorSettings
// Registers // Registers
registers map[rune]core.Register // name -> register registers map[rune]core.Register // name -> register
@ -185,7 +185,7 @@ func (m *Model) processInsertKey(key string) {
} }
case "tab": case "tab":
tabs := strings.Repeat(" ", m.Settings().TabSize) tabs := strings.Repeat(" ", m.Settings().TabStop)
if col < len(l) { if col < len(l) {
buf.SetLine(line, l[:col]+tabs+l[col:]) buf.SetLine(line, l[:col]+tabs+l[col:])
} else { } else {
@ -282,11 +282,11 @@ func (m *Model) SetMode(mode core.Mode) {
m.mode = mode m.mode = mode
} }
func (m *Model) Settings() core.Settings { func (m *Model) Settings() core.EditorSettings {
return m.settings return m.settings
} }
func (m *Model) SetSettings(s core.Settings) { func (m *Model) SetSettings(s core.EditorSettings) {
m.settings = s m.settings = s
} }

View File

@ -93,7 +93,7 @@ func (mb *ModelBuilder) WithTermHeight(height int) *ModelBuilder {
} }
// ModelBuilder.WithSettings: Set the editor settings (tabstop, scrolloff, etc). // ModelBuilder.WithSettings: Set the editor settings (tabstop, scrolloff, etc).
func (mb *ModelBuilder) WithSettings(settings core.Settings) *ModelBuilder { func (mb *ModelBuilder) WithSettings(settings core.EditorSettings) *ModelBuilder {
mb.model.settings = settings mb.model.settings = settings
return mb return mb
} }

View File

@ -19,10 +19,10 @@ func (m Model) View() string {
// Each window has its own status bar and mode // Each window has its own status bar and mode
styles := m.Styles() styles := m.Styles()
settings := m.Settings() options := win.Options
// Draw window // Draw window
view := viewWindow(win, styles, settings, m.Mode()) view := viewWindow(win, styles, options, m.Mode())
// Command bar is seperate // Command bar is seperate
cmdBar := drawCommandBar(m) cmdBar := drawCommandBar(m)
@ -31,7 +31,7 @@ func (m Model) View() string {
// viewWindow: Renders a single window's content including line numbers and buffer text. // viewWindow: Renders a single window's content including line numbers and buffer text.
// Each window has its own line numbers, gutter, and viewport dimensions. // Each window has its own line numbers, gutter, and viewport dimensions.
func viewWindow(w *core.Window, styles style.Styles, settings core.Settings, mode core.Mode) string { func viewWindow(w *core.Window, styles style.Styles, options core.WinOptions, mode core.Mode) string {
buf := w.Buffer buf := w.Buffer
var view strings.Builder var view strings.Builder
@ -42,7 +42,7 @@ func viewWindow(w *core.Window, styles style.Styles, settings core.Settings, mod
// Draw buffer lines // Draw buffer lines
for lineNum := start; lineNum < end; lineNum++ { for lineNum := start; lineNum < end; lineNum++ {
if lineNum < buf.LineCount() { if lineNum < buf.LineCount() {
line := drawLine(w, styles, settings, mode, buf.Line(lineNum), lineNum) line := drawLine(w, styles, options, mode, buf.Line(lineNum), lineNum)
view.WriteString(line) view.WriteString(line)
} }
view.WriteRune('\n') view.WriteRune('\n')
@ -57,7 +57,7 @@ func viewWindow(w *core.Window, styles style.Styles, settings core.Settings, mod
// drawLine: Renders a single line with syntax highlighting, cursor, and visual selection. // drawLine: Renders a single line with syntax highlighting, cursor, and visual selection.
// Handles gutter, cursor rendering, and visual mode highlighting. // Handles gutter, cursor rendering, and visual mode highlighting.
func drawLine(w *core.Window, styles style.Styles, settings core.Settings, mode core.Mode, line string, lineNumber int) string { func drawLine(w *core.Window, styles style.Styles, options core.WinOptions, mode core.Mode, line string, lineNumber int) string {
runes := []rune(line) runes := []rune(line)
curStyle := styles.CursorStyle(mode) curStyle := styles.CursorStyle(mode)
@ -66,7 +66,7 @@ func drawLine(w *core.Window, styles style.Styles, settings core.Settings, mode
var view strings.Builder var view strings.Builder
// Draw gutter first // Draw gutter first
gutter := drawGutter(w, styles, settings, lineNumber) gutter := drawGutter(w, styles, options, lineNumber)
view.WriteString(gutter) view.WriteString(gutter)
// Now draw the line content // Now draw the line content
@ -97,15 +97,15 @@ func drawLine(w *core.Window, styles style.Styles, settings core.Settings, mode
// drawGutter: Renders the line number gutter with support for both absolute and // drawGutter: Renders the line number gutter with support for both absolute and
// relative line numbers, highlighting the current line differently. // relative line numbers, highlighting the current line differently.
func drawGutter(w *core.Window, styles style.Styles, settings core.Settings, curLine int) string { func drawGutter(w *core.Window, styles style.Styles, options core.WinOptions, curLine int) string {
if !(settings.Number || settings.RelativeNumber) { if !(options.Number || options.RelativeNumber) {
return "" return ""
} }
// Required vars // Required vars
var ( var (
view strings.Builder view strings.Builder
gutSize int = settings.GutterSize - 1 // -1 is for padding gutSize int = options.GutterSize - 1 // -1 is for padding
currentLine bool = curLine == w.Cursor.Line currentLine bool = curLine == w.Cursor.Line
lineNumber int lineNumber int
@ -115,7 +115,7 @@ func drawGutter(w *core.Window, styles style.Styles, settings core.Settings, cur
) )
// If we have relative setting, set the numbers relatively // If we have relative setting, set the numbers relatively
if settings.RelativeNumber { if options.RelativeNumber {
if curLine > w.Cursor.Line { if curLine > w.Cursor.Line {
lineNumber = curLine - w.Cursor.Line lineNumber = curLine - w.Cursor.Line
} }
@ -126,7 +126,7 @@ func drawGutter(w *core.Window, styles style.Styles, settings core.Settings, cur
} }
// If we have number setting AND not relative setting OR we are on current line, use current line number // If we have number setting AND not relative setting OR we are on current line, use current line number
if (settings.Number && !settings.RelativeNumber) || (settings.Number && currentLine) { if (options.Number && !options.RelativeNumber) || (options.Number && currentLine) {
lineNumber = curLine + 1 lineNumber = curLine + 1
} }