ronantakizawa/codereview-bench huggingface dataset:
Repository: zyedidia/micro
File: internal/action/command.go (Go)

Code before:
		for _, a := range args {
			b, err := buffer.NewBufferFromFile(a, buffer.BTDefault)
			if err != nil {
				InfoBar.Error(err)
				return
			}
			tp := NewTabFromBuffer(0, 0, width, height-1-iOffset, b)
			Tabs.AddTab(tp)
			Tabs.SetActive(len(Tabs.List) - 1)
		}
	} else {
		b := buffer.NewBufferFromString("", "", buffer.BTDefault)
		tp := NewTabFromBuffer(0, 0, width, height-iOffset, b)
		Tabs.AddTab(tp)
		Tabs.SetActive(len(Tabs.List) - 1)
	}
}

func SetGlobalOptionNative(option string, nativeValue interface{}) error {
	// check for local option first...
	for _, s := range config.LocalSettings {
		if s == option {
			if bp, ok := MainTab().CurPane().(*BufPane); ok {
				bp.Buf.SetOptionNative(option, nativeValue)
			} else {
				InfoBar.Error("This pane doesn't support local options")
			}
			return nil
		}
	}

	// ...if it's not local continue with the globals
	config.GlobalSettings[option] = nativeValue
	config.ModifiedSettings[option] = true
	delete(config.VolatileSettings, option)

	if option == "colorscheme" {
		// LoadSyntaxFiles()
		config.InitColorscheme()
		for _, b := range buffer.OpenBuffers {
			b.UpdateRules()
		}
	} else if option == "infobar" || option == "keymenu" {
		Tabs.Resize()
	} else if option == "mouse" {
		if !nativeValue.(bool) {
			screen.Screen.DisableMouse()
		} else {
			screen.Screen.EnableMouse()
		}
	} else if option == "autosave" {

Review comment (suggestion):
I think this error message is gonna be confusing to the user in *any* scenarios of using `SetGlobalOptionNative()`.

I think `SetGlobalOptionNative()` should not display any error message in the infobar on its own, it should rather *return* an error to the caller.

Code after:
		for _, a := range args {
			b, err := buffer.NewBufferFromFile(a, buffer.BTDefault)
			if err != nil {
				InfoBar.Error(err)
				return
			}
			tp := NewTabFromBuffer(0, 0, width, height-1-iOffset, b)
			Tabs.AddTab(tp)
			Tabs.SetActive(len(Tabs.List) - 1)
		}
	} else {
		b := buffer.NewBufferFromString("", "", buffer.BTDefault)
		tp := NewTabFromBuffer(0, 0, width, height-iOffset, b)
		Tabs.AddTab(tp)
		Tabs.SetActive(len(Tabs.List) - 1)
	}
}

func SetGlobalOptionNative(option string, nativeValue interface{}) error {
	// check for local option first...
	for _, s := range config.LocalSettings {
		if s == option {
			MainTab().CurPane().Buf.SetOptionNative(option, nativeValue)
			return nil
		}
	}

	// ...if it's not local continue with the globals
	config.GlobalSettings[option] = nativeValue
	config.ModifiedSettings[option] = true
	delete(config.VolatileSettings, option)

	if option == "colorscheme" {
		// LoadSyntaxFiles()
		config.InitColorscheme()
		for _, b := range buffer.OpenBuffers {
			b.UpdateRules()
		}
	} else if option == "infobar" || option == "keymenu" {
		Tabs.Resize()
	} else if option == "mouse" {
		if !nativeValue.(bool) {
			screen.Screen.DisableMouse()
		} else {
			screen.Screen.EnableMouse()
		}
	} else if option == "autosave" {
		if nativeValue.(float64) > 0 {
			config.SetAutoTime(int(nativeValue.(float64)))
			config.StartAutoSave()
		} else {
Repository: zyedidia/micro
File: internal/action/bindings.go (Go)

Code before:
			r:    rune(k[0]),
		}, true
	}

	// We don't know what happened.
	return KeyEvent{}, false
}

func findEvent(k string) (Event, error) {
	var event Event
	event, ok, err := findEvents(k)
	if err != nil {
		return nil, err
	}

	if !ok {
		event, ok = findSingleEvent(k)
		if !ok {
			return nil, errors.New(k + " is not a bindable event")
		}
	}

	return event, nil
}

func compareEvents(keyEvent Event, parsed map[string]interface{}) (bool, string) {
	var event string
	keySequence, keyIsKeySequence := keyEvent.(KeySequenceEvent)

parseLoop:
	for event = range parsed {
		if e, err := findEvent(event); err == nil {
			eKeySequence, eIsKeySequence := e.(KeySequenceEvent)
			if eIsKeySequence && keyIsKeySequence {
				if len(eKeySequence.keys) != len(keySequence.keys) {
					continue parseLoop
				}
				for i := 0; i < len(eKeySequence.keys); i++ {
					if eKeySequence.keys[i] != keySequence.keys[i] {
						continue parseLoop
					}
				}

				return true, event
			}
			if e == keyEvent {
				return true, event
			}
		}
	}


Review comment (refactor):
I'd rather add a generic function which would just compare two arbitrary events (i.e. what you are doing at lines 261-276), i.e. just a replacement for `e == key`, nothing more.

If you also want to de-duplicate the outer `for ev := range parsed` loop as well, - ok, maybe that's a good idea too. But that could be implemented separately, in a separate helper function that could, in turn, use this generic comparator function. (And actually it seems this de-duplication is not worth it.)

Code after:
			r:    rune(k[0]),
		}, true
	}

	// We don't know what happened.
	return KeyEvent{}, false
}

func findEvent(k string) (Event, error) {
	var event Event
	event, ok, err := findEvents(k)
	if err != nil {
		return nil, err
	}

	if !ok {
		event, ok = findSingleEvent(k)
		if !ok {
			return nil, errors.New(k + " is not a bindable event")
		}
	}

	return event, nil
}

func eventsEqual(e1 Event, e2 Event) bool {
	seq1, ok1 := e1.(KeySequenceEvent)
	seq2, ok2 := e2.(KeySequenceEvent)
	if ok1 && ok2 {
		if len(seq1.keys) != len(seq2.keys) {
			return false
		}
		for i := 0; i < len(seq1.keys); i++ {
			if seq1.keys[i] != seq2.keys[i] {
				return false
			}
		}
		return true
	}

	return e1 == e2
}

// TryBindKey tries to bind a key by writing to config.ConfigDir/bindings.json
// Returns true if the keybinding already existed and a possible error
func TryBindKey(k, v string, overwrite bool) (bool, error) {
	var e error
	var parsed map[string]interface{}

	filename := filepath.Join(config.ConfigDir, "bindings.json")
	createBindingsIfNotExist(filename)
Repository: zyedidia/micro
File: internal/action/bindings.go (Go)

Code before:

func findEvent(k string) (Event, error) {
	var event Event
	event, ok, err := findEvents(k)
	if err != nil {
		return nil, err
	}

	if !ok {
		event, ok = findSingleEvent(k)
		if !ok {
			return nil, errors.New(k + " is not a bindable event")
		}
	}

	return event, nil
}

func compareEvents(keyEvent Event, parsed map[string]interface{}) (bool, string) {
	var event string
	keySequence, keyIsKeySequence := keyEvent.(KeySequenceEvent)

parseLoop:
	for event = range parsed {
		if e, err := findEvent(event); err == nil {
			eKeySequence, eIsKeySequence := e.(KeySequenceEvent)
			if eIsKeySequence && keyIsKeySequence {
				if len(eKeySequence.keys) != len(keySequence.keys) {
					continue parseLoop
				}
				for i := 0; i < len(eKeySequence.keys); i++ {
					if eKeySequence.keys[i] != keySequence.keys[i] {
						continue parseLoop
					}
				}

				return true, event
			}
			if e == keyEvent {
				return true, event
			}
		}
	}

	return false, event
}

// TryBindKey tries to bind a key by writing to config.ConfigDir/bindings.json
// Returns true if the keybinding already existed and a possible error
func TryBindKey(k, v string, overwrite bool) (bool, error) {
	var e error

Review comment (suggestion):
I'd prefer a more idiomatic and readable way, like:

```
switch e := event.(type) {
case KeySequenceEvent:
	k, ok := keyEvent.(KeySequenceEvent)
	if !ok {
		return false
	}
	for ...
default:
	return event == keyEvent
}
```

Code after:

func findEvent(k string) (Event, error) {
	var event Event
	event, ok, err := findEvents(k)
	if err != nil {
		return nil, err
	}

	if !ok {
		event, ok = findSingleEvent(k)
		if !ok {
			return nil, errors.New(k + " is not a bindable event")
		}
	}

	return event, nil
}

func eventsEqual(e1 Event, e2 Event) bool {
	seq1, ok1 := e1.(KeySequenceEvent)
	seq2, ok2 := e2.(KeySequenceEvent)
	if ok1 && ok2 {
		if len(seq1.keys) != len(seq2.keys) {
			return false
		}
		for i := 0; i < len(seq1.keys); i++ {
			if seq1.keys[i] != seq2.keys[i] {
				return false
			}
		}
		return true
	}

	return e1 == e2
}

// TryBindKey tries to bind a key by writing to config.ConfigDir/bindings.json
// Returns true if the keybinding already existed and a possible error
func TryBindKey(k, v string, overwrite bool) (bool, error) {
	var e error
	var parsed map[string]interface{}

	filename := filepath.Join(config.ConfigDir, "bindings.json")
	createBindingsIfNotExist(filename)
	if _, e = os.Stat(filename); e == nil {
		input, err := ioutil.ReadFile(filename)
		if err != nil {
			return false, errors.New("Error reading bindings.json file: " + err.Error())
		}

		err = json5.Unmarshal(input, &parsed)
Repository: zyedidia/micro
File: internal/action/bindings.go (Go)

Code before:
		}, true
	}

	// We don't know what happened.
	return KeyEvent{}, false
}

func findEvent(k string) (Event, error) {
	var event Event
	event, ok, err := findEvents(k)
	if err != nil {
		return nil, err
	}

	if !ok {
		event, ok = findSingleEvent(k)
		if !ok {
			return nil, errors.New(k + " is not a bindable event")
		}
	}

	return event, nil
}

func compareEvents(a Event, b Event) bool {
	switch aSequence := a.(type) {
	case KeySequenceEvent:
		bSequence, ok := b.(KeySequenceEvent)
		if !ok {
			return false
		}
		if len(aSequence.keys) != len(bSequence.keys) {
			return false
		}
		for i := 0; i < len(aSequence.keys); i++ {
			if aSequence.keys[i] != bSequence.keys[i] {
				return false
			}
		}
		return true
	default:
		return a == b
	}
}

// TryBindKey tries to bind a key by writing to config.ConfigDir/bindings.json
// Returns true if the keybinding already existed and a possible error
func TryBindKey(k, v string, overwrite bool) (bool, error) {
	var e error
	var parsed map[string]interface{}


Review comment (suggestion):
Hmm... My apologies, I've realized that the style I suggested makes it rather confusing in this case: it makes it non-obvious that the function behaves symmetrically with regard to both arguments.

Maybe something like:
```
func equalEvents(e1 Event, e2 Event) {
	seq1, ok1 := e1.(KeySequenceEvent)
	seq2, ok2 := e2.(KeySequenceEvent)
	if ok1 && ok2 {
		...
		return true
	}

	return e1 == e2
}
```

Code after:
		}, true
	}

	// We don't know what happened.
	return KeyEvent{}, false
}

func findEvent(k string) (Event, error) {
	var event Event
	event, ok, err := findEvents(k)
	if err != nil {
		return nil, err
	}

	if !ok {
		event, ok = findSingleEvent(k)
		if !ok {
			return nil, errors.New(k + " is not a bindable event")
		}
	}

	return event, nil
}

func eventsEqual(e1 Event, e2 Event) bool {
	seq1, ok1 := e1.(KeySequenceEvent)
	seq2, ok2 := e2.(KeySequenceEvent)
	if ok1 && ok2 {
		if len(seq1.keys) != len(seq2.keys) {
			return false
		}
		for i := 0; i < len(seq1.keys); i++ {
			if seq1.keys[i] != seq2.keys[i] {
				return false
			}
		}
		return true
	}

	return e1 == e2
}

// TryBindKey tries to bind a key by writing to config.ConfigDir/bindings.json
// Returns true if the keybinding already existed and a possible error
func TryBindKey(k, v string, overwrite bool) (bool, error) {
	var e error
	var parsed map[string]interface{}

	filename := filepath.Join(config.ConfigDir, "bindings.json")
	createBindingsIfNotExist(filename)
	if _, e = os.Stat(filename); e == nil {
Repository: zyedidia/micro
File: internal/action/tab.go (Go)

Code before:
				t.Scroll(-4)
				return
			} else if my == t.Y && mx == t.Width-1 {
				t.Scroll(4)
				return
			}
			if len(t.List) > 1 {
				ind := t.LocFromVisual(buffer.Loc{mx, my})
				if ind != -1 {
					t.SetActive(ind)
					return
				}
				if my == 0 {
					return
				}
			}
		case tcell.ButtonNone:
			if t.List[t.Active()].release {
				// Mouse release received, while already released:
				// Check for unreleased tabs which are resizing and reset them.
				for _, tab := range t.List {
					if !tab.release && tab.resizing != nil {
						tab.resizing = nil
						return
					}
				}
			}
		case tcell.WheelUp:
			if my == t.Y {
				t.Scroll(4)
				return
			}
		case tcell.WheelDown:
			if my == t.Y {
				t.Scroll(-4)
				return
			}
		}
	}
	t.List[t.Active()].HandleEvent(event)
}

// Display updates the names and then displays the tab bar
func (t *TabList) Display() {
	t.UpdateNames()
	if len(t.List) > 1 {
		t.TabWindow.Display()
	}
}

func (t *TabList) SetActive(a int) {

Review comment (suggestion):
It prevents resizing if the active tab changed, but still doesn't prevent it if the screen stopped.

Looks like we should further unify `ReleaseMouse()` which you unified in the next commit (which is nice BTW, thanks), to make it also reset `tab.resizing` for each tab. (And then probably also reuse `ReleaseMouse()` here, instead of adding this custom logic, because why not.)

Code after:
				t.Scroll(-4)
				return
			} else if my == t.Y && mx == t.Width-1 {
				t.Scroll(4)
				return
			}
			if len(t.List) > 1 {
				ind := t.LocFromVisual(buffer.Loc{mx, my})
				if ind != -1 {
					t.SetActive(ind)
					return
				}
				if my == 0 {
					return
				}
			}
		case tcell.ButtonNone:
			if t.List[t.Active()].release {
				// Mouse release received, while already released
				t.ResetMouse()
				return
			}
		case tcell.WheelUp:
			if my == t.Y {
				t.Scroll(4)
				return
			}
		case tcell.WheelDown:
			if my == t.Y {
				t.Scroll(-4)
				return
			}
		}
	}
	t.List[t.Active()].HandleEvent(event)
}

// Display updates the names and then displays the tab bar
func (t *TabList) Display() {
	t.UpdateNames()
	if len(t.List) > 1 {
		t.TabWindow.Display()
	}
}

func (t *TabList) SetActive(a int) {
	t.TabWindow.SetActive(a)

	for i, p := range t.List {
		if i == a {
			if !p.isActive {
Repository: zyedidia/micro
File: internal/action/tab.go (Go)

Code before:
	case *tcell.EventResize:
		t.Resize()
	case *tcell.EventMouse:
		mx, my := e.Position()
		switch e.Buttons() {
		case tcell.Button1:
			if my == t.Y && mx == 0 {
				t.Scroll(-4)
				return
			} else if my == t.Y && mx == t.Width-1 {
				t.Scroll(4)
				return
			}
			if len(t.List) > 1 {
				ind := t.LocFromVisual(buffer.Loc{mx, my})
				if ind != -1 {
					t.SetActive(ind)
					return
				}
				if my == 0 {
					return
				}
			}
		case tcell.ButtonNone:
			if t.List[t.Active()].release {
				// Mouse release received, while already released...reset mouse
				t.ResetMouse()
			}
		case tcell.WheelUp:
			if my == t.Y {
				t.Scroll(4)
				return
			}
		case tcell.WheelDown:
			if my == t.Y {
				t.Scroll(-4)
				return
			}
		}
	}
	t.List[t.Active()].HandleEvent(event)
}

// Display updates the names and then displays the tab bar
func (t *TabList) Display() {
	t.UpdateNames()
	if len(t.List) > 1 {
		t.TabWindow.Display()
	}
}


Review comment (suggestion):
The `...reset mouse` part doesn't look useful. It is clear from the name that `ResetMouse()` resets mouse.

Code after:
	case *tcell.EventResize:
		t.Resize()
	case *tcell.EventMouse:
		mx, my := e.Position()
		switch e.Buttons() {
		case tcell.Button1:
			if my == t.Y && mx == 0 {
				t.Scroll(-4)
				return
			} else if my == t.Y && mx == t.Width-1 {
				t.Scroll(4)
				return
			}
			if len(t.List) > 1 {
				ind := t.LocFromVisual(buffer.Loc{mx, my})
				if ind != -1 {
					t.SetActive(ind)
					return
				}
				if my == 0 {
					return
				}
			}
		case tcell.ButtonNone:
			if t.List[t.Active()].release {
				// Mouse release received, while already released
				t.ResetMouse()
				return
			}
		case tcell.WheelUp:
			if my == t.Y {
				t.Scroll(4)
				return
			}
		case tcell.WheelDown:
			if my == t.Y {
				t.Scroll(-4)
				return
			}
		}
	}
	t.List[t.Active()].HandleEvent(event)
}

// Display updates the names and then displays the tab bar
func (t *TabList) Display() {
	t.UpdateNames()
	if len(t.List) > 1 {
		t.TabWindow.Display()
	}
}
Repository: zyedidia/micro
File: tools/cross-compile.sh (Shell)

Code before:
#!/bin/sh

HASH="$(git rev-parse --short HEAD)"
VERSION="$(go run tools/build-version.go)"
DATE="$(go run tools/build-date.go)"
ADDITIONAL_GO_LINKER_FLAGS="$(go run tools/info-plist.go $VERSION)"

mkdir -p binaries
mkdir -p micro-$VERSION

cp LICENSE micro-$VERSION
cp README.md micro-$VERSION
cp LICENSE-THIRD-PARTY micro-$VERSION
cp assets/packaging/micro.1 micro-$VERSION
cp assets/packaging/micro.desktop micro-$VERSION
cp assets/micro-logo-mark.svg micro-$VERSION/micro.svg

create_artefact_generic()
{
	mv micro micro-$VERSION/
	tar -czf micro-$VERSION-$1.tgz micro-$VERSION
	sha256sum micro-$VERSION-$1.tgz > micro-$VERSION-$1.tgz.sha
	mv micro-$VERSION-$1.* binaries
	rm micro-$VERSION/micro
}


Review comment (bug):
Maybe it's a good idea to use `#!/bin/sh -e`? Any of the commands in this script may potentially fails, so we'd better not ignore such failures silently?

What do these github actions do if the command (`cross-compile.sh` in this case) exits with a non-zero status? I hope they abort the action and log the stderr output?

Code after:
#!/bin/sh

set -e

HASH="$(git rev-parse --short HEAD)"
VERSION="$(go run tools/build-version.go)"
DATE="$(go run tools/build-date.go)"
ADDITIONAL_GO_LINKER_FLAGS="$(go run tools/info-plist.go $VERSION)"

mkdir -p binaries
mkdir -p micro-$VERSION

cp LICENSE micro-$VERSION
cp README.md micro-$VERSION
cp LICENSE-THIRD-PARTY micro-$VERSION
cp assets/packaging/micro.1 micro-$VERSION
cp assets/packaging/micro.desktop micro-$VERSION
cp assets/micro-logo-mark.svg micro-$VERSION/micro.svg

create_artefact_generic()
{
	mv micro micro-$VERSION/
	tar -czf micro-$VERSION-$1.tgz micro-$VERSION
	sha256sum micro-$VERSION-$1.tgz > micro-$VERSION-$1.tgz.sha
	mv micro-$VERSION-$1.* binaries
	rm micro-$VERSION/micro
Repository: zyedidia/micro
File: internal/action/actions.go (Go)

Code before:
	if h.Cursor.HasSelection() {
		origLoc := h.Cursor.Loc
		origLastVisualX := h.Cursor.LastVisualX
		origSelection := h.Cursor.CurSelection

		start := h.Cursor.CurSelection[0]
		end := h.Cursor.CurSelection[1]
		if start.GreaterThan(end) {
			start, end = end, start
		}
		if end.X == 0 {
			end = end.Move(-1, h.Buf)
		}

		h.Cursor.Deselect(true)
		h.Cursor.Loc = end
		h.Cursor.End()
		for y := start.Y; y <= end.Y; y++ {
			h.Buf.Insert(h.Cursor.Loc, "\n"+string(h.Buf.LineBytes(y)))
		}

		h.Cursor.Loc = origLoc
		h.Cursor.LastVisualX = origLastVisualX
		h.Cursor.CurSelection = origSelection

		if start.Y < end.Y {
			InfoBar.Message(fmt.Sprintf("Duplicated %d lines", end.Y-start.Y+1))
		} else {
			InfoBar.Message("Duplicated line")
		}
	} else {
		h.Cursor.End()
		h.Buf.Insert(h.Cursor.Loc, "\n"+string(h.Buf.LineBytes(h.Cursor.Y)))
		InfoBar.Message("Duplicated line")
	}
	h.Relocate()
	return true
}

// DeleteLine deletes the current line. If there is a selection, DeleteLine
// deletes all the lines that are (fully or partially) in the selection.
func (h *BufPane) DeleteLine() bool {
	nlines := h.selectLines()
	if nlines == 0 {
		return false
	}
	h.Cursor.DeleteSelection()
	h.Cursor.ResetSelection()
	h.Cursor.StoreVisualX()
	if nlines > 1 {
		InfoBar.Message(fmt.Sprintf("Deleted %d lines", nlines))

Review comment (refactor):
Minor thing
```suggestion
			InfoBar.Message(fmt.Sprintf("Duplicated %d lines", end.Y - start.Y + 1))
```

Code after:
		origLoc := h.Cursor.Loc
		origLastVisualX := h.Cursor.LastVisualX
		origSelection := h.Cursor.CurSelection

		start := h.Cursor.CurSelection[0]
		end := h.Cursor.CurSelection[1]
		if start.GreaterThan(end) {
			start, end = end, start
		}
		if end.X == 0 {
			end = end.Move(-1, h.Buf)
		}

		h.Cursor.Deselect(true)
		h.Cursor.Loc = end
		h.Cursor.End()
		for y := start.Y; y <= end.Y; y++ {
			h.Buf.Insert(h.Cursor.Loc, "\n"+string(h.Buf.LineBytes(y)))
		}

		h.Cursor.Loc = origLoc
		h.Cursor.LastVisualX = origLastVisualX
		h.Cursor.CurSelection = origSelection

		if start.Y < end.Y {
			InfoBar.Message(fmt.Sprintf("Duplicated %d lines", end.Y-start.Y+1))
		} else {
			InfoBar.Message("Duplicated line")
		}
	} else {
		h.Cursor.End()
		h.Buf.Insert(h.Cursor.Loc, "\n"+string(h.Buf.LineBytes(h.Cursor.Y)))
		InfoBar.Message("Duplicated line")
	}
	h.Relocate()
	return true
}

// DeleteLine deletes the current line. If there is a selection, DeleteLine
// deletes all the lines that are (fully or partially) in the selection.
func (h *BufPane) DeleteLine() bool {
	nlines := h.selectLines()
	if nlines == 0 {
		return false
	}
	h.Cursor.DeleteSelection()
	h.Cursor.ResetSelection()
	h.Cursor.StoreVisualX()
	if nlines > 1 {
		InfoBar.Message(fmt.Sprintf("Deleted %d lines", nlines))
	} else {
Repository: zyedidia/micro
File: internal/action/command.go (Go)

Code before:
	if reloadPlugins {
		config.InitPlugins()
	}

	oldParsedSettings := config.ParsedSettings()

	err := config.ReadSettings()
	if err != nil {
		screen.TermMessage(err)
	}

	parsedSettings := config.ParsedSettings()
	defaultGlobals := config.DefaultGlobalSettings()
	for k := range defaultGlobals {
		if _, ok := parsedSettings[k]; ok {
			SetGlobalOptionNative(k, parsedSettings[k])
			continue
		}
		if _, ok := oldParsedSettings[k]; ok {
			SetGlobalOptionNative(k, defaultGlobals[k])
		}
	}

	if reloadPlugins {
		err = config.LoadAllPlugins()
		if err != nil {
			screen.TermMessage(err)
		}
	}

	InitBindings()
	InitCommands()

	if reloadPlugins {
		err = config.RunPluginFn("preinit")
		if err != nil {
			screen.TermMessage(err)
		}
		err = config.RunPluginFn("init")
		if err != nil {
			screen.TermMessage(err)
		}
		err = config.RunPluginFn("postinit")
		if err != nil {
			screen.TermMessage(err)
		}
	}

	err = config.InitColorscheme()
	if err != nil {
		screen.TermMessage(err)

Review comment (suggestion):
1. We should do this for local settings as well.
2. We should do this for local settings not just in `reload` but also in `set filetype`.

For example, with this in `settings.json`:

```
    "ft:c": {
        "ruler": false
    },
```

open `foo.go`, run `set filetype c` -> the ruler disappears (as expected)

but then run `set filetype go` -> the ruler doesn't appear again.

Code after:

	if reloadPlugins {
		config.InitPlugins()
	}

	err := config.ReadSettings()
	if err != nil {
		screen.TermMessage(err)
	} else {
		parsedSettings := config.ParsedSettings()
		defaultSettings := config.DefaultAllSettings()
		for k := range defaultSettings {
			if _, ok := config.VolatileSettings[k]; ok {
				// reload should not override volatile settings
				continue
			}

			if _, ok := parsedSettings[k]; ok {
				err = doSetGlobalOptionNative(k, parsedSettings[k])
			} else {
				err = doSetGlobalOptionNative(k, defaultSettings[k])
			}
			if err != nil {
				screen.TermMessage(err)
			}
		}
	}

	if reloadPlugins {
		err = config.LoadAllPlugins()
		if err != nil {
			screen.TermMessage(err)
		}
	}

	InitBindings()
	InitCommands()

	if reloadPlugins {
		err = config.RunPluginFn("preinit")
		if err != nil {
			screen.TermMessage(err)
		}
		err = config.RunPluginFn("init")
		if err != nil {
			screen.TermMessage(err)
		}
		err = config.RunPluginFn("postinit")
		if err != nil {
			screen.TermMessage(err)
		}