// Package inputrc parses readline inputrc files.
package inputrc //go:generate go run gen.go import ( ) // Parse parses inputrc data from r. func ( io.Reader, Handler, ...Option) error { return New(...).Parse(, ) } // ParseBytes parses inputrc data from buf. func ( []byte, Handler, ...Option) error { return New(...).Parse(bytes.NewReader(), ) } // ParseFile parses inputrc data from a file name. func ( string, Handler, ...Option) error { , := os.Open() if != nil { return } defer .Close() return New(append(, WithName())...).Parse(, ) } // UserDefault loads default inputrc settings for the user. func ( *user.User, *Config, ...Option) error { // build possible file list var []string if := os.Getenv("INPUTRC"); != "" { = append(, ) } if != nil { := ".inputrc" if runtime.GOOS == "windows" { = "_inputrc" } = append(, filepath.Join(.HomeDir, )) } if runtime.GOOS != "windows" { = append(, "/etc/inputrc") } // load first available file for , := range { , := .ReadFile() switch { case != nil && errors.Is(, os.ErrNotExist): continue case != nil: return } return ParseBytes(, , append(, WithName())...) } return nil } // Unescape unescapes a inputrc string. func ( string) string { := []rune() return unescapeRunes(, 0, len()) } // Escape escapes a inputrc string. func ( string) string { return escape(, map[rune]string{ Delete: `\C-?`, Return: `\C-M`, }) } // EscapeMacro escapes a inputrc macro. func ( string) string { return escape(, map[rune]string{ Delete: `\d`, Return: `\r`, }) } // escape escapes s using m. func escape( string, map[rune]string) string { var []string for , := range { switch { case Alert: = append(, `\a`) case Backspace: = append(, `\b`) case Delete: = append(, [Delete]) // \C-? or \d case Esc: = append(, `\e`) case Formfeed: = append(, `\f`) case Newline: = append(, `\n`) case Return: = append(, [Return]) // \C-M or \r case Tab: = append(, `\t`) case Vertical: = append(, `\v`) case '\\', '"', '\'': = append(, `\`+string()) default: var string if IsControl() { += `\C-` = Decontrol() } if IsMeta() { += `\M-` = Demeta() } if unicode.IsPrint() { += string() } else { += fmt.Sprintf(`\x%2x`, ) } = append(, ) } } return strings.Join(, "") } // Encontrol encodes a Control-c code. func ( rune) rune { return unicode.ToUpper() & Control } // Decontrol decodes a Control-c code. func ( rune) rune { return unicode.ToUpper( | 0x40) } // IsControl returns true when c is a Control-c code. func ( rune) bool { return < Space && &Meta == 0 } // Enmeta encodes a Meta-c code. func ( rune) rune { return | Meta } // Demeta decodes a Meta-c code. func ( rune) rune { return & ^Meta } // IsMeta returns true when c is a Meta-c code. func ( rune) bool { return > Delete && <= 0xff } // Error is a error. type Error string // Errors. const ( // ErrBindMissingClosingQuote is the bind missing closing quote error. ErrBindMissingClosingQuote Error = `bind missing closing quote` // ErrMissingColon is the missing : error. ErrMissingColon Error = "missing :" // ErrMacroMissingClosingQuote is the macro missing closing quote error. ErrMacroMissingClosingQuote Error = `macro missing closing quote` // ErrInvalidKeymap is the invalid keymap error. ErrInvalidKeymap Error = "invalid keymap" // ErrInvalidEditingMode is the invalid editing mode error. ErrInvalidEditingMode Error = "invalid editing mode" // ErrElseWithoutMatchingIf is the $else without matching $if error. ErrElseWithoutMatchingIf Error = "$else without matching $if" // ErrEndifWithoutMatchingIf is the $endif without matching $if error. ErrEndifWithoutMatchingIf Error = "$endif without matching $if" // ErrUnknownModifier is the unknown modifier error. ErrUnknownModifier Error = "unknown modifier" ) // Error satisfies the error interface. func ( Error) () string { return string() } // Keys. const ( Control rune = 0x1f Meta rune = 0x80 Esc rune = 0x1b Delete rune = 0x7f Alert rune = '\a' Backspace rune = '\b' Formfeed rune = '\f' Newline rune = '\n' Return rune = '\r' Tab rune = '\t' Vertical rune = '\v' Space rune = ' ' // Rubout = Delete. )