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

Code before:

			for _, i := range includes {
				if header.FileType == i {
					file, err := highlight.ParseFile(data)
					if err != nil {
						screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error())
						continue
					}
					files = append(files, file)
					break
				}
			}
			if len(files) >= len(includes) {
				break
			}
		}

		highlight.ResolveIncludes(b.SyntaxDef, files)
	}

	if b.Highlighter == nil || syntaxFile != "" {
		if b.SyntaxDef != nil {
			b.Settings["filetype"] = b.SyntaxDef.FileType
		} else {
			// search for the default file in the user's custom syntax files
			name := "default"
			b.SyntaxDef = findRealRuntimeSyntaxDef(name, nil)
			if b.SyntaxDef == nil {
				// search for the default file in the runtime files
				b.SyntaxDef = findRuntimeSyntaxDef(name, nil)
			}
		}
	}

	if b.SyntaxDef != nil {
		b.Highlighter = highlight.NewHighlighter(b.SyntaxDef)
		if b.Settings["syntax"].(bool) {
			go func() {
				b.Highlighter.HighlightStates(b)
				b.Highlighter.HighlightMatches(b, 0, b.End().Y)
				screen.Redraw()
			}()
		}
	}
}

// ClearMatches clears all of the syntax highlighting for the buffer
func (b *Buffer) ClearMatches() {
	for i := range b.lines {
		b.SetMatch(i, nil)
		b.SetState(i, nil)

Review comment (suggestion):
Extra variable seems a bit excessive, I'd just "hardcode" `"default"` in both function calls. (BTW it is "hardcoded" also at the beginning of `UpdateRules()`, right? So it if your intention is to avoid harcoding it in more than one place, you should use a variable in all 3 places? But anyway, it seems excessive to me anyway.)

Code after:
			for _, i := range includes {
				if header.FileType == i {
					file, err := highlight.ParseFile(data)
					if err != nil {
						screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error())
						continue
					}
					files = append(files, file)
					break
				}
			}
			if len(files) >= len(includes) {
				break
			}
		}

		highlight.ResolveIncludes(b.SyntaxDef, files)
	}

	if b.Highlighter == nil || syntaxFile != "" {
		if b.SyntaxDef != nil {
			b.Settings["filetype"] = b.SyntaxDef.FileType
		} else {
			// search for the default file in the user's custom syntax files
			b.SyntaxDef = findRealRuntimeSyntaxDef("default", nil)
			if b.SyntaxDef == nil {
				// search for the default file in the runtime files
				b.SyntaxDef = findRuntimeSyntaxDef("default", nil)
			}
		}
	}

	if b.SyntaxDef != nil {
		b.Highlighter = highlight.NewHighlighter(b.SyntaxDef)
		if b.Settings["syntax"].(bool) {
			go func() {
				b.Highlighter.HighlightStates(b)
				b.Highlighter.HighlightMatches(b, 0, b.End().Y)
				screen.Redraw()
			}()
		}
	}
}

// ClearMatches clears all of the syntax highlighting for the buffer
func (b *Buffer) ClearMatches() {
	for i := range b.lines {
		b.SetMatch(i, nil)
		b.SetState(i, nil)
	}
}
Repository: zyedidia/micro
File: internal/buffer/buffer.go (Go)

Code before:
		}
		size += n

		for _, l := range b.lines[1:] {
			n, e = h.Write([]byte{'\n'})
			if e != nil {
				return e
			}
			size += n
			n, e = h.Write(l.data)
			if e != nil {
				return e
			}
			size += n
		}
	}

	if size > LargeFileThreshold {
		return ErrFileTooLarge
	}

	h.Sum((*out)[:0])
	return nil
}

// parseDefFromFile can be used to generalize the syntax file parsing
func parseDefFromFile(f config.RuntimeFile, header *highlight.Header) *highlight.Def {
	data, err := f.Data()
	if err != nil {
		screen.TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
		return nil
	}

	if header == nil {
		header, err = highlight.MakeHeaderYaml(data)
		if err != nil {
			screen.TermMessage("Error parsing header for syntax file " + f.Name() + ": " + err.Error())
			return nil
		}
	}

	file, err := highlight.ParseFile(data)
	if err != nil {
		screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error())
		return nil
	}

	syndef, err := highlight.ParseDef(file, header)
	if err != nil {
		screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error())
		return nil

Review comment (refactor):
nit: It doesn't sound quite clear what does it mean to "generalize the syntax file parsing".

Actually I guess we can just remove this comment, it's more or less obvious what does this function do anyway.

Code after:
		}
		size += n

		for _, l := range b.lines[1:] {
			n, e = h.Write([]byte{'\n'})
			if e != nil {
				return e
			}
			size += n
			n, e = h.Write(l.data)
			if e != nil {
				return e
			}
			size += n
		}
	}

	if size > LargeFileThreshold {
		return ErrFileTooLarge
	}

	h.Sum((*out)[:0])
	return nil
}

func parseDefFromFile(f config.RuntimeFile, header *highlight.Header) *highlight.Def {
	data, err := f.Data()
	if err != nil {
		screen.TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
		return nil
	}

	if header == nil {
		header, err = highlight.MakeHeaderYaml(data)
		if err != nil {
			screen.TermMessage("Error parsing header for syntax file " + f.Name() + ": " + err.Error())
			return nil
		}
	}

	file, err := highlight.ParseFile(data)
	if err != nil {
		screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error())
		return nil
	}

	syndef, err := highlight.ParseDef(file, header)
	if err != nil {
		screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error())
		return nil
	}
Repository: zyedidia/micro
File: internal/action/bindings.go (Go)

Code before:
	}

	return event, nil
}

// 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)
		if err != nil {
			return false, errors.New("Error reading bindings.json: " + err.Error())
		}

		// Convert possible received string of raw escape sequence
		k = strings.ReplaceAll(k, "\\x1b", "\x1b")

		key, err := findEvent(k)
		if err != nil {
			return false, err
		}

		found := false
		for ev := range parsed {
			if e, err := findEvent(ev); err == nil {
				if e == key {
					if overwrite {
						parsed[ev] = v
					}
					found = true
					break
				}
			}
		}

		if found && !overwrite {
			return true, nil
		} else if !found {
			parsed[k] = v
		}


Review comment (suggestion):
`TryBindKey()` is also used from Lua, so this escaping might mess up with Lua's own escaping of its strings. So perhaps it's better to do it in `BindCmd()`, not here? (i.e. do it only on the UI level, specifically for the `bind` command)

(I see that, although Lua >=5.2 [supports](https://www.lua.org/manual/5.2/manual.html#3.1) `\x` hex escaping in its strings, it doesn't work in micro. The reason is that [gopher-lua](https://github.com/yuin/gopher-lua) implements only Lua 5.1, as it explicitly states. But it may change in the future...)

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

	return event, nil
}

// 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)
		if err != nil {
			return false, errors.New("Error reading bindings.json: " + err.Error())
		}

		key, err := findEvent(k)
		if err != nil {
			return false, err
		}

		found := false
		for ev := range parsed {
			if e, err := findEvent(ev); err == nil {
				if e == key {
					if overwrite {
						parsed[ev] = v
					}
					found = true
					break
				}
			}
		}

		if found && !overwrite {
			return true, nil
		} else if !found {
			parsed[k] = v
		}
Repository: zyedidia/micro
File: internal/action/command.go (Go)

Code before:
	}

	var option interface{}
	if opt, ok := h.Buf.Settings[args[0]]; ok {
		option = opt
	} else if opt, ok := config.GlobalSettings[args[0]]; ok {
		option = opt
	}

	if option == nil {
		InfoBar.Error(args[0], " is not a valid option")
		return
	}

	InfoBar.Message(option)
}

// ShowKeyCmd displays the action that a key is bound to
func (h *BufPane) ShowKeyCmd(args []string) {
	if len(args) < 1 {
		InfoBar.Error("Please provide a key to show")
		return
	}

	// Convert possible received string of raw escape sequence
	args[0] = ConvertRawEscFromString2Byte(args[0])

	event, err := findEvent(args[0])
	if err != nil {
		InfoBar.Error(err)
		return
	}
	if action, ok := config.Bindings["buffer"][event.Name()]; ok {
		InfoBar.Message(action)
	} else {
		InfoBar.Message(args[0], " has no binding")
	}
}

// BindCmd creates a new keybinding
func (h *BufPane) BindCmd(args []string) {
	if len(args) < 2 {
		InfoBar.Error("Not enough arguments")
		return
	}

	// Convert possible received string of raw escape sequence
	args[0] = ConvertRawEscFromString2Byte(args[0])

	_, err := TryBindKey(args[0], args[1], true)
	if err != nil {

Review comment (suggestion):
I would use it directly without intermediate assignment, e.g. `TryBindKey(convertRawEscStr2Byte(args[0]), args[1], true)`.

Code after:
		option = opt
	} else if opt, ok := config.GlobalSettings[args[0]]; ok {
		option = opt
	}

	if option == nil {
		InfoBar.Error(args[0], " is not a valid option")
		return
	}

	InfoBar.Message(option)
}

func parseKeyArg(arg string) string {
	// If this is a raw escape sequence, convert it to its raw byte form
	return strings.ReplaceAll(arg, "\\x1b", "\x1b")
}

// ShowKeyCmd displays the action that a key is bound to
func (h *BufPane) ShowKeyCmd(args []string) {
	if len(args) < 1 {
		InfoBar.Error("Please provide a key to show")
		return
	}

	event, err := findEvent(parseKeyArg(args[0]))
	if err != nil {
		InfoBar.Error(err)
		return
	}
	if action, ok := config.Bindings["buffer"][event.Name()]; ok {
		InfoBar.Message(action)
	} else {
		InfoBar.Message(args[0], " has no binding")
	}
}

// BindCmd creates a new keybinding
func (h *BufPane) BindCmd(args []string) {
	if len(args) < 2 {
		InfoBar.Error("Not enough arguments")
		return
	}

	_, err := TryBindKey(parseKeyArg(args[0]), args[1], true)
	if err != nil {
		InfoBar.Error(err)
	}
}

// UnbindCmd binds a key to its default action
Repository: zyedidia/micro
File: internal/action/command.go (Go)

Code before:
}

// ShowCmd shows the value of the given option
func (h *BufPane) ShowCmd(args []string) {
	if len(args) < 1 {
		InfoBar.Error("Please provide an option to show")
		return
	}

	var option interface{}
	if opt, ok := h.Buf.Settings[args[0]]; ok {
		option = opt
	} else if opt, ok := config.GlobalSettings[args[0]]; ok {
		option = opt
	}

	if option == nil {
		InfoBar.Error(args[0], " is not a valid option")
		return
	}

	InfoBar.Message(option)
}

// Convert possible received string of raw escape sequence to a hexadecimal byte
func convertRawEsc2Hex(rawEsc string) string {
	return strings.ReplaceAll(rawEsc, "\\x1b", "\x1b")
}

// ShowKeyCmd displays the action that a key is bound to
func (h *BufPane) ShowKeyCmd(args []string) {
	if len(args) < 1 {
		InfoBar.Error("Please provide a key to show")
		return
	}

	event, err := findEvent(convertRawEsc2Hex(args[0]))
	if err != nil {
		InfoBar.Error(err)
		return
	}
	if action, ok := config.Bindings["buffer"][event.Name()]; ok {
		InfoBar.Message(action)
	} else {
		InfoBar.Message(args[0], " has no binding")
	}
}

// BindCmd creates a new keybinding
func (h *BufPane) BindCmd(args []string) {
	if len(args) < 2 {

Review comment (security):
Just noticed this `2Hex` and it seems doesn't make much sense to me. What is a "hexadecimal byte"? It is just a byte.

...So now I have another pedantic suggestion: rename this function to something simple and "generic" like `parseKeyArg()` (i.e. without mentioning raw escape sequence in the function name) and move the comment into the function. Rationale: in most cases we do nothing to this string, we only convert it if it's a raw esc sequence, which is only a special corner case, so let's not emphasize this corner case too much in the code. Also it will make this function "extensible".

And the comment itself I would reword a bit to be more clear, something like "If this is a raw escape sequence, convert it to its raw byte form".

Code after:
}

// ShowCmd shows the value of the given option
func (h *BufPane) ShowCmd(args []string) {
	if len(args) < 1 {
		InfoBar.Error("Please provide an option to show")
		return
	}

	var option interface{}
	if opt, ok := h.Buf.Settings[args[0]]; ok {
		option = opt
	} else if opt, ok := config.GlobalSettings[args[0]]; ok {
		option = opt
	}

	if option == nil {
		InfoBar.Error(args[0], " is not a valid option")
		return
	}

	InfoBar.Message(option)
}

func parseKeyArg(arg string) string {
	// If this is a raw escape sequence, convert it to its raw byte form
	return strings.ReplaceAll(arg, "\\x1b", "\x1b")
}

// ShowKeyCmd displays the action that a key is bound to
func (h *BufPane) ShowKeyCmd(args []string) {
	if len(args) < 1 {
		InfoBar.Error("Please provide a key to show")
		return
	}

	event, err := findEvent(parseKeyArg(args[0]))
	if err != nil {
		InfoBar.Error(err)
		return
	}
	if action, ok := config.Bindings["buffer"][event.Name()]; ok {
		InfoBar.Message(action)
	} else {
		InfoBar.Message(args[0], " has no binding")
	}
}

// BindCmd creates a new keybinding
func (h *BufPane) BindCmd(args []string) {
	if len(args) < 2 {
Repository: zyedidia/micro
File: internal/action/command.go (Go)

Code before:
// QuitCmd closes the main view
func (h *BufPane) QuitCmd(args []string) {
	h.Quit()
}

func convertLine(h *BufPane, line string) (int, error) {
	lineNum, err := strconv.Atoi(line)
	relative := false
	if err != nil {
		return 0, err
	}

	// Check for relative numbers
	if strings.Contains(line, "-") || strings.Contains(line, "+") {
		lineNum = h.Buf.GetActiveCursor().Y + 1 + lineNum
		relative = true
	}

	if relative {
		// Handle wrap-over
		if lineNum <= 0 {
			lineNum = h.Buf.LinesNum() + 1 + lineNum
		} else if lineNum > h.Buf.LinesNum() {
			lineNum = lineNum - h.Buf.LinesNum()
		} else {
			// fits
		}
	}
	lineNum = util.Clamp(lineNum-1, 0, h.Buf.LinesNum()-1)

	return lineNum, err
}

// GotoCmd is a command that will send the cursor to a certain
// position in the buffer
// For example: `goto line`, or `goto line:col`
func (h *BufPane) GotoCmd(args []string) {
	if len(args) <= 0 {
		InfoBar.Error("Not enough arguments")
	} else {
		h.RemoveAllMultiCursors()
		if strings.Contains(args[0], ":") {
			parts := strings.SplitN(args[0], ":", 2)
			line, err := convertLine(h, parts[0])
			if err != nil {
				InfoBar.Error(err)
				return
			}
			col, err := strconv.Atoi(parts[1])
			if err != nil {
				InfoBar.Error(err)

Review comment (suggestion):
I don't think this wrapping makes sense. I think we should just clamp it between the beginning and the end of file, that's the behavior I would expect as a user.

(Actually this clamping is already done below. So now the behavior is even more confusing: we wrap once, and if it still doesn't fit, we clamp it.)

Code after:
// QuitCmd closes the main view
func (h *BufPane) QuitCmd(args []string) {
	h.Quit()
}

func convertLine(h *BufPane, line string) (int, error) {
	lineNum := 0
	var err error

	// Check for special negative movement beginning from the end of the file
	if strings.HasPrefix(line, "~") {
		lineNum, err = strconv.Atoi(line[1:])
		if err != nil {
			return 0, err
		}
		lineNum = h.Buf.LinesNum() + 1 - lineNum
	} else {
		lineNum, err = strconv.Atoi(line)
		if err != nil {
			return 0, err
		}

		// Check for relative numbers
		if strings.HasPrefix(line, "-") || strings.HasPrefix(line, "+") {
			lineNum = h.Buf.GetActiveCursor().Y + 1 + lineNum
		}
	}

	lineNum = util.Clamp(lineNum-1, 0, h.Buf.LinesNum()-1)

	return lineNum, err
}

// GotoCmd is a command that will send the cursor to a certain
// position in the buffer
// For example: `goto line`, or `goto line:col`
func (h *BufPane) GotoCmd(args []string) {
	if len(args) <= 0 {
		InfoBar.Error("Not enough arguments")
	} else {
		line, col := 0, 0
		var err error
		h.RemoveAllMultiCursors()
		if strings.Contains(args[0], ":") {
			parts := strings.SplitN(args[0], ":", 2)
			line, err = convertLine(h, parts[0])
			if err != nil {
				InfoBar.Error(err)
				return
			}
			col, err = strconv.Atoi(parts[1])
Repository: zyedidia/micro
File: internal/action/command.go (Go)

Code before:
			}
			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 {
	local := false
	for _, s := range config.LocalSettings {
		if s == option {
			local = true
			break
		}
	}

	if local {
		MainTab().CurPane().Buf.SetOptionNative(option, nativeValue)
		return nil
	} else {
		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 {
				config.SetAutoTime(0)
			}

Review comment (refactor):
`else` is not needed after `return`, and that's what I actually had in mind. We can move the bulk of the function out of this `if`, since we are done with the `local` case and can forget about it.

For cleanliness all this can be done in 2 separate commits (no matter in which order): the actual fix for unneeded rewriting and the refactoring.

Code after:
				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 {
			config.SetAutoTime(0)
		}
	} else if option == "paste" {
Repository: zyedidia/micro
File: internal/action/infocomplete.go (Go)

Code before:
	return chosen, suggestions
}

// filetypeComplete autocompletes filetype
func filetypeComplete(input string) (string, []string) {
	var suggestions []string

	// Since we need to complete the file type instead of the file name
	// we need to parse the RTSyntax* files and search for a matching FileType.
	// The following logic can be simplified to the previos state again,
	// in the moment the file names will represent the file types directly.
	for _, f := range config.ListRealRuntimeFiles(config.RTSyntax) {
		data, err := f.Data()
		if err != nil {
			continue
		}
		header, err := highlight.MakeHeaderYaml(data)
		if err != nil {
			continue
		}
		if strings.HasPrefix(header.FileType, input) {
			suggestions = append(suggestions, header.FileType)
		}
	}
headerLoop:
	for _, f := range config.ListRuntimeFiles(config.RTSyntaxHeader) {
		data, err := f.Data()
		if err != nil {
			continue
		}
		header, err := highlight.MakeHeader(data)
		if err != nil {
			continue
		}
		for _, v := range suggestions {
			if v == header.FileType {
				continue headerLoop
			}
		}
		if strings.HasPrefix(header.FileType, input) {
			suggestions = append(suggestions, header.FileType)
		}
	}

	if strings.HasPrefix("off", input) {
		suggestions = append(suggestions, "off")
	}
	if strings.HasPrefix("unknown", input) {
		suggestions = append(suggestions, "unknown")
	}


Review comment (bug):
If the user (wrongfully) adds a file with `filetype: "unknown"` or `filetype: "off"` to `~/.config/micro/syntax`, we get duplicated suggestions for `unknown` or `off`.

Code after:
	return chosen, suggestions
}

// filetypeComplete autocompletes filetype
func filetypeComplete(input string) (string, []string) {
	var suggestions []string

	// We cannot match filetypes just by names of syntax files,
	// since those names may be different from the actual filetype values
	// specified inside syntax files (e.g. "c++" filetype in cpp.yaml).
	// So we need to parse filetype values out of those files.
	for _, f := range config.ListRealRuntimeFiles(config.RTSyntax) {
		data, err := f.Data()
		if err != nil {
			continue
		}
		header, err := highlight.MakeHeaderYaml(data)
		if err != nil {
			continue
		}
		// Prevent duplicated defaults
		if header.FileType == "off" || header.FileType == "unknown" {
			continue
		}
		if strings.HasPrefix(header.FileType, input) {
			suggestions = append(suggestions, header.FileType)
		}
	}
headerLoop:
	for _, f := range config.ListRuntimeFiles(config.RTSyntaxHeader) {
		data, err := f.Data()
		if err != nil {
			continue
		}
		header, err := highlight.MakeHeader(data)
		if err != nil {
			continue
		}
		for _, v := range suggestions {
			if v == header.FileType {
				continue headerLoop
			}
		}
		if strings.HasPrefix(header.FileType, input) {
			suggestions = append(suggestions, header.FileType)
		}
	}

	if strings.HasPrefix("off", input) {
		suggestions = append(suggestions, "off")
	}