|
1 | 1 | package xcode |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "bytes" |
4 | 5 | "context" |
5 | 6 | "fmt" |
6 | 7 | "io" |
@@ -141,10 +142,33 @@ func parseXcodeConfig(xmlData []byte) (*xcodeKeybindingsPlist, error) { |
141 | 142 | var plistData xcodeKeybindingsPlist |
142 | 143 |
|
143 | 144 | // Use plist library to decode the plist data |
144 | | - _, err := plist.Unmarshal(xmlData, &plistData) |
| 145 | + sanitized := sanitizeXcodePlist(xmlData) |
| 146 | + _, err := plist.Unmarshal(sanitized, &plistData) |
145 | 147 | if err != nil { |
146 | 148 | return nil, fmt.Errorf("failed to decode plist: %w", err) |
147 | 149 | } |
148 | 150 |
|
149 | 151 | return &plistData, nil |
150 | 152 | } |
| 153 | + |
| 154 | +const unknownKeyCode = 0x03 |
| 155 | + |
| 156 | +// FIXME(xinnjie): plist is XML 1.0. XML 1.0 forbids most control characters (everything below 0x20 except 0x09, 0x0A, 0x0D) |
| 157 | +// `U+0003` is sometimes included in Xcode generated keybinding, though it is not valid XML, but is valid in Xcode idekeybindings file |
| 158 | +// I don't know why Xcode generates this keybinding. |
| 159 | +// change `U+0003` to `F20`(which is hardly used too) in xcode plist for now. |
| 160 | +func sanitizeXcodePlist(data []byte) []byte { |
| 161 | + if bytes.IndexByte(data, unknownKeyCode) == -1 { |
| 162 | + return data |
| 163 | + } |
| 164 | + replacement := []byte(string(rune(xcodeF24))) |
| 165 | + out := make([]byte, 0, len(data)) |
| 166 | + for i := range data { |
| 167 | + if data[i] == unknownKeyCode { |
| 168 | + out = append(out, replacement...) |
| 169 | + } else { |
| 170 | + out = append(out, data[i]) |
| 171 | + } |
| 172 | + } |
| 173 | + return out |
| 174 | +} |
0 commit comments