diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index 2735ca467c..3a5861352e 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -443,7 +443,7 @@ func NewBuffer(r io.Reader, size int64, path string, btype BufType, cmd Command) b.UpdateRules() // we know the filetype now, so update per-filetype settings - config.UpdateFileTypeLocals(b.Settings, b.Settings["filetype"].(string)) + config.UpdateFileTypeLocals(b.Settings, settingAsString(b.Settings["filetype"], "unknown")) if _, err := os.Stat(filepath.Join(config.ConfigDir, "buffers")); errors.Is(err, fs.ErrNotExist) { os.Mkdir(filepath.Join(config.ConfigDir, "buffers"), os.ModePerm) @@ -575,7 +575,7 @@ func (b *Buffer) Remove(start, end Loc) { // FileType returns the buffer's filetype func (b *Buffer) FileType() string { - return b.Settings["filetype"].(string) + return settingAsString(b.Settings["filetype"], "unknown") } // ExternallyModified returns whether the file being edited has @@ -818,7 +818,7 @@ func (b *Buffer) UpdateRules() { if !b.Type.Syntax { return } - ft := b.Settings["filetype"].(string) + ft := settingAsString(b.Settings["filetype"], "unknown") if ft == "off" { b.ClearMatches() b.SyntaxDef = nil diff --git a/internal/buffer/settings.go b/internal/buffer/settings.go index e2178726ce..980355c722 100644 --- a/internal/buffer/settings.go +++ b/internal/buffer/settings.go @@ -12,11 +12,22 @@ import ( luar "layeh.com/gopher-luar" ) +// settingAsString safely converts a settings value to string. +// If the value is not a string (e.g. a map from a glob/ft config entry), +// it falls back to the provided default. This prevents TypeAssertionError +// panics when config values are unexpectedly non-string (see issue #4042). +func settingAsString(v any, defaultVal string) string { + if s, ok := v.(string); ok { + return s + } + return defaultVal +} + func (b *Buffer) ReloadSettings(reloadFiletype bool) { settings := config.ParsedSettings() config.UpdatePathGlobLocals(settings, b.AbsPath) - oldFiletype := b.Settings["filetype"].(string) + oldFiletype := settingAsString(b.Settings["filetype"], "unknown") _, local := b.LocalSettings["filetype"] _, volatile := config.VolatileSettings["filetype"] @@ -24,14 +35,18 @@ func (b *Buffer) ReloadSettings(reloadFiletype bool) { // need to update filetype before updating other settings based on it b.Settings["filetype"] = "unknown" if v, ok := settings["filetype"]; ok { - b.Settings["filetype"] = v + // Only accept string values for filetype; non-string values + // (e.g. a map from a glob config block) are silently ignored. + if ft, ok := v.(string); ok { + b.Settings["filetype"] = ft + } } } // update syntax rules, which will also update filetype if needed b.UpdateRules() - curFiletype := b.Settings["filetype"].(string) + curFiletype := settingAsString(b.Settings["filetype"], "unknown") if oldFiletype != curFiletype { b.doCallbacks("filetype", oldFiletype, curFiletype) }