Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce the available string option validators and add autocompletion for them #3021

Merged
merged 3 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 7 additions & 23 deletions internal/action/infocomplete.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,36 +192,20 @@ func OptionValueComplete(b *buffer.Buffer) ([]string, []string) {
_, suggestions = colorschemeComplete(input)
case "filetype":
_, suggestions = filetypeComplete(input)
case "fileformat":
if strings.HasPrefix("unix", input) {
suggestions = append(suggestions, "unix")
}
if strings.HasPrefix("dos", input) {
suggestions = append(suggestions, "dos")
}
case "sucmd":
if strings.HasPrefix("sudo", input) {
suggestions = append(suggestions, "sudo")
}
if strings.HasPrefix("doas", input) {
suggestions = append(suggestions, "doas")
}
case "clipboard":
if strings.HasPrefix("external", input) {
suggestions = append(suggestions, "external")
}
if strings.HasPrefix("internal", input) {
suggestions = append(suggestions, "internal")
}
if strings.HasPrefix("terminal", input) {
suggestions = append(suggestions, "terminal")
}
case "matchbracestyle":
if strings.HasPrefix("underline", input) {
suggestions = append(suggestions, "underline")
}
if strings.HasPrefix("highlight", input) {
suggestions = append(suggestions, "highlight")
default:
if choices, ok := config.OptionChoices[inputOpt]; ok {
for _, choice := range choices {
if strings.HasPrefix(choice, input) {
suggestions = append(suggestions, choice)
}
}
}
}
}
Expand Down
305 changes: 129 additions & 176 deletions internal/config/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,116 @@ import (

type optionValidator func(string, interface{}) error

// a list of settings that need option validators
var optionValidators = map[string]optionValidator{
"autosave": validateNonNegativeValue,
"clipboard": validateChoice,
"colorcolumn": validateNonNegativeValue,
"colorscheme": validateColorscheme,
"detectlimit": validateNonNegativeValue,
"encoding": validateEncoding,
"fileformat": validateChoice,
"matchbracestyle": validateChoice,
"multiopen": validateChoice,
"reload": validateChoice,
"scrollmargin": validateNonNegativeValue,
"scrollspeed": validateNonNegativeValue,
"tabsize": validatePositiveValue,
}

// a list of settings with pre-defined choices
var OptionChoices = map[string][]string{
"clipboard": {"internal", "external", "terminal"},
"fileformat": {"unix", "dos"},
"matchbracestyle": {"underline", "highlight"},
"multiopen": {"tab", "hsplit", "vsplit"},
"reload": {"prompt", "auto", "disabled"},
}

// a list of settings that can be globally and locally modified and their
// default values
var defaultCommonSettings = map[string]interface{}{
"autoindent": true,
"autosu": false,
"backup": true,
"backupdir": "",
"basename": false,
"colorcolumn": float64(0),
"cursorline": true,
"detectlimit": float64(100),
"diffgutter": false,
"encoding": "utf-8",
"eofnewline": true,
"fastdirty": false,
"fileformat": defaultFileFormat(),
"filetype": "unknown",
"hlsearch": false,
"hltaberrors": false,
"hltrailingws": false,
"incsearch": true,
"ignorecase": true,
"indentchar": " ",
"keepautoindent": false,
"matchbrace": true,
"matchbracestyle": "underline",
"mkparents": false,
"permbackup": false,
"readonly": false,
"reload": "prompt",
"rmtrailingws": false,
"ruler": true,
"relativeruler": false,
"savecursor": false,
"saveundo": false,
"scrollbar": false,
"scrollmargin": float64(3),
"scrollspeed": float64(2),
"smartpaste": true,
"softwrap": false,
"splitbottom": true,
"splitright": true,
"statusformatl": "$(filename) $(modified)($(line),$(col)) $(status.paste)| ft:$(opt:filetype) | $(opt:fileformat) | $(opt:encoding)",
"statusformatr": "$(bind:ToggleKeyMenu): bindings, $(bind:ToggleHelp): help",
"statusline": true,
"syntax": true,
"tabmovement": false,
"tabsize": float64(4),
"tabstospaces": false,
"useprimary": true,
"wordwrap": false,
}

// a list of settings that should only be globally modified and their
// default values
var DefaultGlobalOnlySettings = map[string]interface{}{
"autosave": float64(0),
"clipboard": "external",
"colorscheme": "default",
"divchars": "|-",
"divreverse": true,
"fakecursor": false,
"infobar": true,
"keymenu": false,
"mouse": true,
"multiopen": "tab",
"parsecursor": false,
"paste": false,
"pluginchannels": []string{"https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json"},
"pluginrepos": []string{},
"savehistory": true,
"scrollbarchar": "|",
"sucmd": "sudo",
"tabhighlight": false,
"tabreverse": true,
"xterm": false,
}

// a list of settings that should never be globally modified
var LocalSettings = []string{
"filetype",
"readonly",
}

var (
ErrInvalidOption = errors.New("Invalid option")
ErrInvalidValue = errors.New("Invalid value")
Expand All @@ -46,23 +156,6 @@ func init() {
parsedSettings = make(map[string]interface{})
}

// Options with validators
var optionValidators = map[string]optionValidator{
"autosave": validateNonNegativeValue,
"clipboard": validateClipboard,
"detectlimit": validateNonNegativeValue,
"tabsize": validatePositiveValue,
"scrollmargin": validateNonNegativeValue,
"scrollspeed": validateNonNegativeValue,
"colorscheme": validateColorscheme,
"colorcolumn": validateNonNegativeValue,
"fileformat": validateLineEnding,
"encoding": validateEncoding,
"multiopen": validateMultiOpen,
"reload": validateReload,
"matchbracestyle": validateMatchBraceStyle,
}

func ReadSettings() error {
filename := filepath.Join(ConfigDir, "settings.json")
if _, e := os.Stat(filename); e == nil {
Expand Down Expand Up @@ -258,57 +351,6 @@ func GetGlobalOption(name string) interface{} {
return GlobalSettings[name]
}

var defaultCommonSettings = map[string]interface{}{
"autoindent": true,
"autosu": false,
"backup": true,
"backupdir": "",
"basename": false,
"colorcolumn": float64(0),
"cursorline": true,
"detectlimit": float64(100),
"diffgutter": false,
"encoding": "utf-8",
"eofnewline": true,
"fastdirty": false,
"fileformat": defaultFileFormat(),
"filetype": "unknown",
"hlsearch": false,
"hltaberrors": false,
"hltrailingws": false,
"incsearch": true,
"ignorecase": true,
"indentchar": " ",
"keepautoindent": false,
"matchbrace": true,
"matchbracestyle": "underline",
"mkparents": false,
"permbackup": false,
"readonly": false,
"reload": "prompt",
"rmtrailingws": false,
"ruler": true,
"relativeruler": false,
"savecursor": false,
"saveundo": false,
"scrollbar": false,
"scrollmargin": float64(3),
"scrollspeed": float64(2),
"smartpaste": true,
"softwrap": false,
"splitbottom": true,
"splitright": true,
"statusformatl": "$(filename) $(modified)($(line),$(col)) $(status.paste)| ft:$(opt:filetype) | $(opt:fileformat) | $(opt:encoding)",
"statusformatr": "$(bind:ToggleKeyMenu): bindings, $(bind:ToggleHelp): help",
"statusline": true,
"syntax": true,
"tabmovement": false,
"tabsize": float64(4),
"tabstospaces": false,
"useprimary": true,
"wordwrap": false,
}

func defaultFileFormat() string {
if runtime.GOOS == "windows" {
return "dos"
Expand Down Expand Up @@ -337,37 +379,6 @@ func DefaultCommonSettings() map[string]interface{} {
return commonsettings
}

// a list of settings that should only be globally modified and their
// default values
var DefaultGlobalOnlySettings = map[string]interface{}{
"autosave": float64(0),
"clipboard": "external",
"colorscheme": "default",
"divchars": "|-",
"divreverse": true,
"fakecursor": false,
"infobar": true,
"keymenu": false,
"mouse": true,
"multiopen": "tab",
"parsecursor": false,
"paste": false,
"pluginchannels": []string{"https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json"},
"pluginrepos": []string{},
"savehistory": true,
"scrollbarchar": "|",
"sucmd": "sudo",
"tabhighlight": false,
"tabreverse": true,
"xterm": false,
}

// a list of settings that should never be globally modified
var LocalSettings = []string{
"filetype",
"readonly",
}

// DefaultGlobalSettings returns the default global settings for micro
// Note that colorscheme is a global only option
func DefaultGlobalSettings() map[string]interface{} {
Expand Down Expand Up @@ -461,45 +472,35 @@ func validateNonNegativeValue(option string, value interface{}) error {
return nil
}

func validateColorscheme(option string, value interface{}) error {
colorscheme, ok := value.(string)

if !ok {
return errors.New("Expected string type for colorscheme")
}

if !ColorschemeExists(colorscheme) {
return errors.New(colorscheme + " is not a valid colorscheme")
}

return nil
}

func validateClipboard(option string, value interface{}) error {
val, ok := value.(string)
func validateChoice(option string, value interface{}) error {
if choices, ok := OptionChoices[option]; ok {
val, ok := value.(string)
if !ok {
return errors.New("Expected string type for " + option)
}

if !ok {
return errors.New("Expected string type for clipboard")
}
for _, v := range choices {
if val == v {
return nil
}
}

switch val {
case "internal", "external", "terminal":
default:
return errors.New(option + " must be 'internal', 'external', or 'terminal'")
choicesStr := strings.Join(choices, ", ")
return errors.New(option + " must be one of: " + choicesStr)
}

return nil
return errors.New("Option has no pre-defined choices")
}

func validateLineEnding(option string, value interface{}) error {
endingType, ok := value.(string)
func validateColorscheme(option string, value interface{}) error {
colorscheme, ok := value.(string)

if !ok {
return errors.New("Expected string type for file format")
return errors.New("Expected string type for colorscheme")
}

if endingType != "unix" && endingType != "dos" {
return errors.New("File format must be either 'unix' or 'dos'")
if !ColorschemeExists(colorscheme) {
return errors.New(colorscheme + " is not a valid colorscheme")
}

return nil
Expand All @@ -509,51 +510,3 @@ func validateEncoding(option string, value interface{}) error {
_, err := htmlindex.Get(value.(string))
return err
}

func validateMultiOpen(option string, value interface{}) error {
val, ok := value.(string)

if !ok {
return errors.New("Expected string type for multiopen")
}

switch val {
case "tab", "hsplit", "vsplit":
default:
return errors.New(option + " must be 'tab', 'hsplit', or 'vsplit'")
}

return nil
}

func validateReload(option string, value interface{}) error {
val, ok := value.(string)

if !ok {
return errors.New("Expected string type for reload")
}

switch val {
case "prompt", "auto", "disabled":
default:
return errors.New(option + " must be 'prompt', 'auto' or 'disabled'")
}

return nil
}

func validateMatchBraceStyle(option string, value interface{}) error {
val, ok := value.(string)

if !ok {
errors.New("Expected string type for matchbracestyle")
}

switch val {
case "underline", "highlight":
default:
return errors.New(option + " must be 'underline' or 'highlight'")
}

return nil
}
Loading