2 # Copyright Simon Lydell 2015, 2016.
4 # This file is part of VimFx.
6 # VimFx is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # VimFx is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with VimFx. If not, see <http://www.gnu.org/licenses/>.
20 # This file parses string prefs into more easily used data structures.
22 defaults = require('./defaults')
23 prefs = require('./prefs')
24 utils = require('./utils')
26 MIN_NUM_HINT_CHARS = 2
29 # Parsed options are not stored in Firefox’s prefs system, and are therefore
30 # always read from the defaults. The only way to override them is via the
32 if pref of defaults.parsed_options
33 return defaults.parsed_options[pref]
35 value = prefs.get(pref)
38 {parsed, normalized} = parsers[pref](value, defaults.all_options[pref])
39 if normalized? and normalized != value and prefs.has(pref)
40 prefs.set(pref, normalized)
45 # Splits a whitespace delimited string into an array, with empty elements and
46 # duplicates filtered.
47 parseSpaceDelimitedString = (value) ->
48 parsed = utils.removeDuplicates(value.split(/\s+/)).filter(Boolean)
49 return {parsed, normalized: parsed.join(' ')}
51 parseHintChars = (value, defaultValue) ->
52 [leading..., end] = value.trim().split(/\s+/)
53 parsed = if leading.length > 0 then "#{leading.join('')} #{end}" else end
54 parsed = utils.removeDuplicateCharacters(parsed)
56 # Make sure that hint chars contain at least the required amount of chars.
57 diff = MIN_NUM_HINT_CHARS - parsed.length
59 parsed = parsed + defaultValue[...diff]
61 unless parsed.includes(' ')
62 numDefaultSecondaryHintChars =
63 defaultValue.length - 1 - defaultValue.indexOf(' ')
64 index = Math.min(parsed.length // 2, numDefaultSecondaryHintChars)
65 parsed = "#{parsed[...-index]} #{parsed[-index..]}"
67 return {parsed, normalized: parsed}
69 parsePatterns = (value) ->
70 result = parseSpaceDelimitedString(value)
71 # The patterns are case insensitive regexes and must match either in the
72 # beginning or at the end of a string. They do not match in the middle of
73 # words, so "previous" does not match "previously" (`previous\S*` can be used
74 # for that case). Note: `\s` is used instead of `\b` since it works better
75 # with non-English characters.
76 result.parsed = result.parsed.map((pattern) ->
79 RegExp(pattern).source
81 utils.regexEscape(pattern)
83 ^\s* (?:#{patternRegex}) (?:\s|$)
85 (?:\s|^) (?:#{patternRegex}) \s*$
90 parseBlacklist = (value) ->
91 result = parseSpaceDelimitedString(value)
92 result.parsed = result.parsed.map((pattern) ->
93 return ///^#{utils.regexEscape(pattern).replace(/\\\*/g, '.*')}$///i
98 hint_chars: parseHintChars
100 prev_patterns: parsePatterns
101 next_patterns: parsePatterns
103 blacklist: parseBlacklist
105 prevent_autofocus_modes: parseSpaceDelimitedString
107 adjustable_element_keys: parseSpaceDelimitedString
108 activatable_element_keys: parseSpaceDelimitedString
110 pattern_attrs: parseSpaceDelimitedString
113 module.exports = parsePref