1import os
2
3from .exceptions import ArgcompleteException
4from .io import debug
5from .packages import _shlex
6
7
8def split_line(line, point=None):
9 if point is None:
10 point = len(line)
11 line = line[:point]
12 lexer = _shlex.shlex(line, posix=True)
13 lexer.whitespace_split = True
14 lexer.wordbreaks = os.environ.get("_ARGCOMPLETE_COMP_WORDBREAKS", "")
15 words = []
16
17 def split_word(word):
18 # TODO: make this less ugly
19 point_in_word = len(word) + point - lexer.instream.tell()
20 if isinstance(lexer.state, (str, bytes)) and lexer.state in lexer.whitespace:
21 point_in_word += 1
22 if point_in_word > len(word):
23 debug("In trailing whitespace")
24 words.append(word)
25 word = ""
26 prefix, suffix = word[:point_in_word], word[point_in_word:]
27 prequote = ""
28 # posix
29 if lexer.state is not None and lexer.state in lexer.quotes:
30 prequote = lexer.state
31 # non-posix
32 # if len(prefix) > 0 and prefix[0] in lexer.quotes:
33 # prequote, prefix = prefix[0], prefix[1:]
34
35 return prequote, prefix, suffix, words, lexer.last_wordbreak_pos
36
37 while True:
38 try:
39 word = lexer.get_token()
40 if word == lexer.eof:
41 # TODO: check if this is ever unsafe
42 # raise ArgcompleteException("Unexpected end of input")
43 return "", "", "", words, None
44 if lexer.instream.tell() >= point:
45 debug("word", word, "split, lexer state: '{s}'".format(s=lexer.state))
46 return split_word(word)
47 words.append(word)
48 except ValueError:
49 debug("word", lexer.token, "split (lexer stopped, state: '{s}')".format(s=lexer.state))
50 if lexer.instream.tell() >= point:
51 return split_word(lexer.token)
52 else:
53 msg = (
54 "Unexpected internal state. "
55 "Please report this bug at https://github.com/kislyuk/argcomplete/issues."
56 )
57 raise ArgcompleteException(msg)