2 from __future__ import absolute_import
9 class QuoteError(Exception):
13 def _quotesplit(line):
18 for i in range(len(line)):
21 if inquote == q and c != q:
22 word += '\\' # single-q backslashes can only quote single-q
29 # this is un-sh-like, but do it for sanity when autocompleting
30 yield (wordstart, word)
33 elif not inquote and not word and (c == q or c == qq):
34 # the 'not word' constraint on this is un-sh-like, but do it
35 # for sanity when autocompleting
38 elif not inquote and c in [' ', '\n', '\r', '\t']:
40 yield (wordstart, word)
46 yield (wordstart, word)
47 if inquote or inescape or word:
52 """Split 'line' into a list of offset,word tuples.
54 The words are produced after removing doublequotes, singlequotes, and
57 Note that this implementation isn't entirely sh-compatible. It only
58 dequotes words that *start* with a quote character, that is, a string like
60 will not have its quotes removed, while a string like
62 will be turned into [(0, 'hello'), (6, 'world')] (ie. quotes removed).
66 for i in _quotesplit(line):
73 def unfinished_word(line):
74 """Returns the quotechar,word of any unfinished word at the end of 'line'.
76 You can use this to determine if 'line' is a completely parseable line
77 (ie. one that quotesplit() will finish successfully) or if you need
78 to read more bytes first.
83 quotechar,word: the initial quote char (or None), and the partial word.
86 for (wordstart,word) in _quotesplit(line):
89 firstchar = line[wordstart]
90 if firstchar in [q, qq]:
91 return (firstchar, word)
98 def quotify(qtype, word, terminate):
99 """Return a string corresponding to given word, quoted using qtype.
101 The resulting string is dequotable using quotesplit() and can be
102 joined with other quoted strings by adding arbitrary whitespace
106 qtype: one of '', shquote.qq, or shquote.q
107 word: the string to quote. May contain arbitrary characters.
108 terminate: include the trailing quote character, if any.
113 return qq + word.replace(qq, '\\"') + (terminate and qq or '')
115 return q + word.replace(q, "\\'") + (terminate and q or '')
117 return re.sub(r'([\"\' \t\n\r])', r'\\\1', word)
120 def quotify_list(words):
121 """Return a minimally-quoted string produced by quoting each word.
123 This calculates the qtype for each word depending on whether the word
124 already includes singlequote characters, doublequote characters, both,
128 words: the list of words to quote.
130 The resulting string, with quoted words separated by ' '.
135 if word and not re.search(r'[\s\"\']', word):
137 elif q in word and qq not in word:
139 wordout.append(quotify(qtype, word, True))
140 return ' '.join(wordout)
143 def what_to_add(qtype, origword, newword, terminate):
144 """Return a qtype that is needed to finish a partial word.
146 For example, given an origword of '\"frog' and a newword of '\"frogston',
148 terminate=False: 'ston'
149 terminate=True: 'ston\"'
151 This is useful when calculating tab completion strings for readline.
154 qtype: the type of quoting to use (ie. the first character of origword)
155 origword: the original word that needs completion.
156 newword: the word we want it to be after completion. Must start with
158 terminate: true if we should add the actual quote character at the end.
160 The string to append to origword to produce (quoted) newword.
162 if not newword.startswith(origword):
165 qold = quotify(qtype, origword, terminate=False)
166 return quotify(qtype, newword, terminate=terminate)[len(qold):]