|
@@
-126,7
+126,7
b' import warnings'
|
|
126
|
from contextlib import contextmanager
|
|
126
|
from contextlib import contextmanager
|
|
127
|
from importlib import import_module
|
|
127
|
from importlib import import_module
|
|
128
|
from types import SimpleNamespace
|
|
128
|
from types import SimpleNamespace
|
|
129
|
from typing import Iterable, Iterator, List, Tuple
|
|
129
|
from typing import Iterable, Iterator, List, Tuple, Union, Any, Sequence, Dict, NamedTuple, Pattern, Optional
|
|
130
|
|
|
130
|
|
|
131
|
from IPython.core.error import TryNext
|
|
131
|
from IPython.core.error import TryNext
|
|
132
|
from IPython.core.inputtransformer2 import ESC_MAGIC
|
|
132
|
from IPython.core.inputtransformer2 import ESC_MAGIC
|
|
@@
-156,6
+156,14
b' except ImportError:'
|
|
156
|
# Globals
|
|
156
|
# Globals
|
|
157
|
#-----------------------------------------------------------------------------
|
|
157
|
#-----------------------------------------------------------------------------
|
|
158
|
|
|
158
|
|
|
|
|
|
159
|
# ranges where we have most of the valid unicode names. We could be more finer
|
|
|
|
|
160
|
# grained but is it worth it for performace While unicode have character in the
|
|
|
|
|
161
|
# rage 0, 0x110000, we seem to have name for about 10% of those. (131808 as I
|
|
|
|
|
162
|
# write this). With below range we cover them all, with a density of ~67%
|
|
|
|
|
163
|
# biggest next gap we consider only adds up about 1% density and there are 600
|
|
|
|
|
164
|
# gaps that would need hard coding.
|
|
|
|
|
165
|
_UNICODE_RANGES = [(32, 0x2fa1e), (0xe0001, 0xe01f0)]
|
|
|
|
|
166
|
|
|
159
|
# Public API
|
|
167
|
# Public API
|
|
160
|
__all__ = ['Completer','IPCompleter']
|
|
168
|
__all__ = ['Completer','IPCompleter']
|
|
161
|
|
|
169
|
|
|
@@
-745,7
+753,7
b' def get__all__entries(obj):'
|
|
745
|
return [w for w in words if isinstance(w, str)]
|
|
753
|
return [w for w in words if isinstance(w, str)]
|
|
746
|
|
|
754
|
|
|
747
|
|
|
755
|
|
|
748
|
def match_dict_keys(keys: List[str], prefix: str, delims: str):
|
|
756
|
def match_dict_keys(keys: List[Union[str, bytes]], prefix: str, delims: str) -> Tuple[str, int, List[str]]:
|
|
749
|
"""Used by dict_key_matches, matching the prefix to a list of keys
|
|
757
|
"""Used by dict_key_matches, matching the prefix to a list of keys
|
|
750
|
|
|
758
|
|
|
751
|
Parameters
|
|
759
|
Parameters
|
|
@@
-766,22
+774,25
b' def match_dict_keys(keys: List[str], prefix: str, delims: str):'
|
|
766
|
``matches`` a list of replacement/completion
|
|
774
|
``matches`` a list of replacement/completion
|
|
767
|
|
|
775
|
|
|
768
|
"""
|
|
776
|
"""
|
|
|
|
|
777
|
keys = [k for k in keys if isinstance(k, (str, bytes))]
|
|
769
|
if not prefix:
|
|
778
|
if not prefix:
|
|
770
|
return None, 0, [repr(k) for k in keys
|
|
779
|
return '', 0, [repr(k) for k in keys
|
|
771
|
if isinstance(k, (str, bytes))]
|
|
780
|
if isinstance(k, (str, bytes))]
|
|
772
|
quote_match = re.search('["\']', prefix)
|
|
781
|
quote_match = re.search('["\']', prefix)
|
|
|
|
|
782
|
assert quote_match is not None # silence mypy
|
|
773
|
quote = quote_match.group()
|
|
783
|
quote = quote_match.group()
|
|
774
|
try:
|
|
784
|
try:
|
|
775
|
prefix_str = eval(prefix + quote, {})
|
|
785
|
prefix_str = eval(prefix + quote, {})
|
|
776
|
except Exception:
|
|
786
|
except Exception:
|
|
777
|
return None, 0, []
|
|
787
|
return '', 0, []
|
|
778
|
|
|
788
|
|
|
779
|
pattern = '[^' + ''.join('\\' + c for c in delims) + ']*$'
|
|
789
|
pattern = '[^' + ''.join('\\' + c for c in delims) + ']*$'
|
|
780
|
token_match = re.search(pattern, prefix, re.UNICODE)
|
|
790
|
token_match = re.search(pattern, prefix, re.UNICODE)
|
|
|
|
|
791
|
assert token_match is not None # silence mypy
|
|
781
|
token_start = token_match.start()
|
|
792
|
token_start = token_match.start()
|
|
782
|
token_prefix = token_match.group()
|
|
793
|
token_prefix = token_match.group()
|
|
783
|
|
|
794
|
|
|
784
|
matched = []
|
|
795
|
matched:List[str] = []
|
|
785
|
for key in keys:
|
|
796
|
for key in keys:
|
|
786
|
try:
|
|
797
|
try:
|
|
787
|
if not key.startswith(prefix_str):
|
|
798
|
if not key.startswith(prefix_str):
|
|
@@
-794,14
+805,6
b' def match_dict_keys(keys: List[str], prefix: str, delims: str):'
|
|
794
|
rem = key[len(prefix_str):]
|
|
805
|
rem = key[len(prefix_str):]
|
|
795
|
# force repr wrapped in '
|
|
806
|
# force repr wrapped in '
|
|
796
|
rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"')
|
|
807
|
rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"')
|
|
797
|
if rem_repr.startswith('u') and prefix[0] not in 'uU':
|
|
|
|
|
798
|
# Found key is unicode, but prefix is Py2 string.
|
|
|
|
|
799
|
# Therefore attempt to interpret key as string.
|
|
|
|
|
800
|
try:
|
|
|
|
|
801
|
rem_repr = repr(rem.encode('ascii') + '"')
|
|
|
|
|
802
|
except UnicodeEncodeError:
|
|
|
|
|
803
|
continue
|
|
|
|
|
804
|
|
|
|
|
|
805
|
rem_repr = rem_repr[1 + rem_repr.index("'"):-2]
|
|
808
|
rem_repr = rem_repr[1 + rem_repr.index("'"):-2]
|
|
806
|
if quote == '"':
|
|
809
|
if quote == '"':
|
|
807
|
# The entered prefix is quoted with ",
|
|
810
|
# The entered prefix is quoted with ",
|
|
@@
-887,9
+890,8
b' def _safe_isinstance(obj, module, class_name):'
|
|
887
|
return (module in sys.modules and
|
|
890
|
return (module in sys.modules and
|
|
888
|
isinstance(obj, getattr(import_module(module), class_name)))
|
|
891
|
isinstance(obj, getattr(import_module(module), class_name)))
|
|
889
|
|
|
892
|
|
|
890
|
|
|
893
|
def back_unicode_name_matches(text:str) -> Tuple[str, Sequence[str]]:
|
|
891
|
def back_unicode_name_matches(text):
|
|
894
|
"""Match Unicode characters back to Unicode name
|
|
892
|
u"""Match unicode characters back to unicode name
|
|
|
|
|
893
|
|
|
895
|
|
|
894
|
This does ``☃`` -> ``\\snowman``
|
|
896
|
This does ``☃`` -> ``\\snowman``
|
|
895
|
|
|
897
|
|
|
@@
-898,52
+900,60
b' def back_unicode_name_matches(text):'
|
|
898
|
|
|
900
|
|
|
899
|
This will not either back-complete standard sequences like \\n, \\b ...
|
|
901
|
This will not either back-complete standard sequences like \\n, \\b ...
|
|
900
|
|
|
902
|
|
|
901
|
Used on Python 3 only.
|
|
903
|
Returns
|
|
|
|
|
904
|
=======
|
|
|
|
|
905
|
|
|
|
|
|
906
|
Return a tuple with two elements:
|
|
|
|
|
907
|
|
|
|
|
|
908
|
- The Unicode character that was matched (preceded with a backslash), or
|
|
|
|
|
909
|
empty string,
|
|
|
|
|
910
|
- a sequence (of 1), name for the match Unicode character, preceded by
|
|
|
|
|
911
|
backslash, or empty if no match.
|
|
|
|
|
912
|
|
|
902
|
"""
|
|
913
|
"""
|
|
903
|
if len(text)<2:
|
|
914
|
if len(text)<2:
|
|
904
|
return u'', ()
|
|
915
|
return '', ()
|
|
905
|
maybe_slash = text[-2]
|
|
916
|
maybe_slash = text[-2]
|
|
906
|
if maybe_slash != '\\':
|
|
917
|
if maybe_slash != '\\':
|
|
907
|
return u'', ()
|
|
918
|
return '', ()
|
|
908
|
|
|
919
|
|
|
909
|
char = text[-1]
|
|
920
|
char = text[-1]
|
|
910
|
# no expand on quote for completion in strings.
|
|
921
|
# no expand on quote for completion in strings.
|
|
911
|
# nor backcomplete standard ascii keys
|
|
922
|
# nor backcomplete standard ascii keys
|
|
912
|
if char in string.ascii_letters or char in ['"',"'"]:
|
|
923
|
if char in string.ascii_letters or char in ('"',"'"):
|
|
913
|
return u'', ()
|
|
924
|
return '', ()
|
|
914
|
try :
|
|
925
|
try :
|
|
915
|
unic = unicodedata.name(char)
|
|
926
|
unic = unicodedata.name(char)
|
|
916
|
return '\\'+char,['\\'+unic]
|
|
927
|
return '\\'+char,('\\'+unic,)
|
|
917
|
except KeyError:
|
|
928
|
except KeyError:
|
|
918
|
pass
|
|
929
|
pass
|
|
919
|
return u'', ()
|
|
930
|
return '', ()
|
|
920
|
|
|
931
|
|
|
921
|
def back_latex_name_matches(text:str):
|
|
932
|
def back_latex_name_matches(text:str) -> Tuple[str, Sequence[str]] :
|
|
922
|
"""Match latex characters back to unicode name
|
|
933
|
"""Match latex characters back to unicode name
|
|
923
|
|
|
934
|
|
|
924
|
This does ``\\ℵ`` -> ``\\aleph``
|
|
935
|
This does ``\\ℵ`` -> ``\\aleph``
|
|
925
|
|
|
936
|
|
|
926
|
Used on Python 3 only.
|
|
|
|
|
927
|
"""
|
|
937
|
"""
|
|
928
|
if len(text)<2:
|
|
938
|
if len(text)<2:
|
|
929
|
return u'', ()
|
|
939
|
return '', ()
|
|
930
|
maybe_slash = text[-2]
|
|
940
|
maybe_slash = text[-2]
|
|
931
|
if maybe_slash != '\\':
|
|
941
|
if maybe_slash != '\\':
|
|
932
|
return u'', ()
|
|
942
|
return '', ()
|
|
933
|
|
|
943
|
|
|
934
|
|
|
944
|
|
|
935
|
char = text[-1]
|
|
945
|
char = text[-1]
|
|
936
|
# no expand on quote for completion in strings.
|
|
946
|
# no expand on quote for completion in strings.
|
|
937
|
# nor backcomplete standard ascii keys
|
|
947
|
# nor backcomplete standard ascii keys
|
|
938
|
if char in string.ascii_letters or char in ['"',"'"]:
|
|
948
|
if char in string.ascii_letters or char in ('"',"'"):
|
|
939
|
return u'', ()
|
|
949
|
return '', ()
|
|
940
|
try :
|
|
950
|
try :
|
|
941
|
latex = reverse_latex_symbol[char]
|
|
951
|
latex = reverse_latex_symbol[char]
|
|
942
|
# '\\' replace the \ as well
|
|
952
|
# '\\' replace the \ as well
|
|
943
|
return '\\'+char,[latex]
|
|
953
|
return '\\'+char,[latex]
|
|
944
|
except KeyError:
|
|
954
|
except KeyError:
|
|
945
|
pass
|
|
955
|
pass
|
|
946
|
return u'', ()
|
|
956
|
return '', ()
|
|
947
|
|
|
957
|
|
|
948
|
|
|
958
|
|
|
949
|
def _formatparamchildren(parameter) -> str:
|
|
959
|
def _formatparamchildren(parameter) -> str:
|
|
@@
-1002,9
+1012,19
b' def _make_signature(completion)-> str:'
|
|
1002
|
return '(%s)'% ', '.join([f for f in (_formatparamchildren(p) for signature in completion.get_signatures()
|
|
1012
|
return '(%s)'% ', '.join([f for f in (_formatparamchildren(p) for signature in completion.get_signatures()
|
|
1003
|
for p in signature.defined_names()) if f])
|
|
1013
|
for p in signature.defined_names()) if f])
|
|
1004
|
|
|
1014
|
|
|
|
|
|
1015
|
|
|
|
|
|
1016
|
class _CompleteResult(NamedTuple):
|
|
|
|
|
1017
|
matched_text : str
|
|
|
|
|
1018
|
matches: Sequence[str]
|
|
|
|
|
1019
|
matches_origin: Sequence[str]
|
|
|
|
|
1020
|
jedi_matches: Any
|
|
|
|
|
1021
|
|
|
|
|
|
1022
|
|
|
1005
|
class IPCompleter(Completer):
|
|
1023
|
class IPCompleter(Completer):
|
|
1006
|
"""Extension of the completer class with IPython-specific features"""
|
|
1024
|
"""Extension of the completer class with IPython-specific features"""
|
|
1007
|
|
|
1025
|
|
|
|
|
|
1026
|
__dict_key_regexps: Optional[Dict[bool,Pattern]] = None
|
|
|
|
|
1027
|
|
|
1008
|
@observe('greedy')
|
|
1028
|
@observe('greedy')
|
|
1009
|
def _greedy_changed(self, change):
|
|
1029
|
def _greedy_changed(self, change):
|
|
1010
|
"""update the splitter and readline delims when greedy is changed"""
|
|
1030
|
"""update the splitter and readline delims when greedy is changed"""
|
|
@@
-1143,7
+1163,7
b' class IPCompleter(Completer):'
|
|
1143
|
self._unicode_names = None
|
|
1163
|
self._unicode_names = None
|
|
1144
|
|
|
1164
|
|
|
1145
|
@property
|
|
1165
|
@property
|
|
1146
|
def matchers(self):
|
|
1166
|
def matchers(self) -> List[Any]:
|
|
1147
|
"""All active matcher routines for completion"""
|
|
1167
|
"""All active matcher routines for completion"""
|
|
1148
|
if self.dict_keys_only:
|
|
1168
|
if self.dict_keys_only:
|
|
1149
|
return [self.dict_key_matches]
|
|
1169
|
return [self.dict_key_matches]
|
|
@@
-1165,7
+1185,7
b' class IPCompleter(Completer):'
|
|
1165
|
self.dict_key_matches,
|
|
1185
|
self.dict_key_matches,
|
|
1166
|
]
|
|
1186
|
]
|
|
1167
|
|
|
1187
|
|
|
1168
|
def all_completions(self, text) -> List[str]:
|
|
1188
|
def all_completions(self, text:str) -> List[str]:
|
|
1169
|
"""
|
|
1189
|
"""
|
|
1170
|
Wrapper around the completion methods for the benefit of emacs.
|
|
1190
|
Wrapper around the completion methods for the benefit of emacs.
|
|
1171
|
"""
|
|
1191
|
"""
|
|
@@
-1176,14
+1196,14
b' class IPCompleter(Completer):'
|
|
1176
|
|
|
1196
|
|
|
1177
|
return self.complete(text)[1]
|
|
1197
|
return self.complete(text)[1]
|
|
1178
|
|
|
1198
|
|
|
1179
|
def _clean_glob(self, text):
|
|
1199
|
def _clean_glob(self, text:str):
|
|
1180
|
return self.glob("%s*" % text)
|
|
1200
|
return self.glob("%s*" % text)
|
|
1181
|
|
|
1201
|
|
|
1182
|
def _clean_glob_win32(self,text):
|
|
1202
|
def _clean_glob_win32(self, text:str):
|
|
1183
|
return [f.replace("\\","/")
|
|
1203
|
return [f.replace("\\","/")
|
|
1184
|
for f in self.glob("%s*" % text)]
|
|
1204
|
for f in self.glob("%s*" % text)]
|
|
1185
|
|
|
1205
|
|
|
1186
|
def file_matches(self, text):
|
|
1206
|
def file_matches(self, text:str)->List[str]:
|
|
1187
|
"""Match filenames, expanding ~USER type strings.
|
|
1207
|
"""Match filenames, expanding ~USER type strings.
|
|
1188
|
|
|
1208
|
|
|
1189
|
Most of the seemingly convoluted logic in this completer is an
|
|
1209
|
Most of the seemingly convoluted logic in this completer is an
|
|
@@
-1265,7
+1285,7
b' class IPCompleter(Completer):'
|
|
1265
|
# Mark directories in input list by appending '/' to their names.
|
|
1285
|
# Mark directories in input list by appending '/' to their names.
|
|
1266
|
return [x+'/' if os.path.isdir(x) else x for x in matches]
|
|
1286
|
return [x+'/' if os.path.isdir(x) else x for x in matches]
|
|
1267
|
|
|
1287
|
|
|
1268
|
def magic_matches(self, text):
|
|
1288
|
def magic_matches(self, text:str):
|
|
1269
|
"""Match magics"""
|
|
1289
|
"""Match magics"""
|
|
1270
|
# Get all shell magics now rather than statically, so magics loaded at
|
|
1290
|
# Get all shell magics now rather than statically, so magics loaded at
|
|
1271
|
# runtime show up too.
|
|
1291
|
# runtime show up too.
|
|
@@
-1356,7
+1376,7
b' class IPCompleter(Completer):'
|
|
1356
|
if color.startswith(prefix) ]
|
|
1376
|
if color.startswith(prefix) ]
|
|
1357
|
return []
|
|
1377
|
return []
|
|
1358
|
|
|
1378
|
|
|
1359
|
def _jedi_matches(self, cursor_column:int, cursor_line:int, text:str):
|
|
1379
|
def _jedi_matches(self, cursor_column:int, cursor_line:int, text:str) -> Iterable[Any]:
|
|
1360
|
"""
|
|
1380
|
"""
|
|
1361
|
|
|
1381
|
|
|
1362
|
Return a list of :any:`jedi.api.Completions` object from a ``text`` and
|
|
1382
|
Return a list of :any:`jedi.api.Completions` object from a ``text`` and
|
|
@@
-1430,7
+1450,7
b' class IPCompleter(Completer):'
|
|
1430
|
else:
|
|
1450
|
else:
|
|
1431
|
return []
|
|
1451
|
return []
|
|
1432
|
|
|
1452
|
|
|
1433
|
def python_matches(self, text):
|
|
1453
|
def python_matches(self, text:str)->List[str]:
|
|
1434
|
"""Match attributes or global python names"""
|
|
1454
|
"""Match attributes or global python names"""
|
|
1435
|
if "." in text:
|
|
1455
|
if "." in text:
|
|
1436
|
try:
|
|
1456
|
try:
|
|
@@
-1512,7
+1532,7
b' class IPCompleter(Completer):'
|
|
1512
|
|
|
1532
|
|
|
1513
|
return list(set(ret))
|
|
1533
|
return list(set(ret))
|
|
1514
|
|
|
1534
|
|
|
1515
|
def python_func_kw_matches(self,text):
|
|
1535
|
def python_func_kw_matches(self, text):
|
|
1516
|
"""Match named parameters (kwargs) of the last open function"""
|
|
1536
|
"""Match named parameters (kwargs) of the last open function"""
|
|
1517
|
|
|
1537
|
|
|
1518
|
if "." in text: # a parameter cannot be dotted
|
|
1538
|
if "." in text: # a parameter cannot be dotted
|
|
@@
-1582,36
+1602,39
b' class IPCompleter(Completer):'
|
|
1582
|
# Remove used named arguments from the list, no need to show twice
|
|
1602
|
# Remove used named arguments from the list, no need to show twice
|
|
1583
|
for namedArg in set(namedArgs) - usedNamedArgs:
|
|
1603
|
for namedArg in set(namedArgs) - usedNamedArgs:
|
|
1584
|
if namedArg.startswith(text):
|
|
1604
|
if namedArg.startswith(text):
|
|
1585
|
argMatches.append(u"%s=" %namedArg)
|
|
1605
|
argMatches.append("%s=" %namedArg)
|
|
1586
|
except:
|
|
1606
|
except:
|
|
1587
|
pass
|
|
1607
|
pass
|
|
1588
|
|
|
1608
|
|
|
1589
|
return argMatches
|
|
1609
|
return argMatches
|
|
1590
|
|
|
1610
|
|
|
1591
|
def dict_key_matches(self, text):
|
|
1611
|
@staticmethod
|
|
|
|
|
1612
|
def _get_keys(obj: Any) -> List[Any]:
|
|
|
|
|
1613
|
# Objects can define their own completions by defining an
|
|
|
|
|
1614
|
# _ipy_key_completions_() method.
|
|
|
|
|
1615
|
method = get_real_method(obj, '_ipython_key_completions_')
|
|
|
|
|
1616
|
if method is not None:
|
|
|
|
|
1617
|
return method()
|
|
|
|
|
1618
|
|
|
|
|
|
1619
|
# Special case some common in-memory dict-like types
|
|
|
|
|
1620
|
if isinstance(obj, dict) or\
|
|
|
|
|
1621
|
_safe_isinstance(obj, 'pandas', 'DataFrame'):
|
|
|
|
|
1622
|
try:
|
|
|
|
|
1623
|
return list(obj.keys())
|
|
|
|
|
1624
|
except Exception:
|
|
|
|
|
1625
|
return []
|
|
|
|
|
1626
|
elif _safe_isinstance(obj, 'numpy', 'ndarray') or\
|
|
|
|
|
1627
|
_safe_isinstance(obj, 'numpy', 'void'):
|
|
|
|
|
1628
|
return obj.dtype.names or []
|
|
|
|
|
1629
|
return []
|
|
|
|
|
1630
|
|
|
|
|
|
1631
|
def dict_key_matches(self, text:str) -> List[str]:
|
|
1592
|
"Match string keys in a dictionary, after e.g. 'foo[' "
|
|
1632
|
"Match string keys in a dictionary, after e.g. 'foo[' "
|
|
1593
|
def get_keys(obj):
|
|
|
|
|
1594
|
# Objects can define their own completions by defining an
|
|
|
|
|
1595
|
# _ipy_key_completions_() method.
|
|
|
|
|
1596
|
method = get_real_method(obj, '_ipython_key_completions_')
|
|
|
|
|
1597
|
if method is not None:
|
|
|
|
|
1598
|
return method()
|
|
|
|
|
1599
|
|
|
|
|
|
1600
|
# Special case some common in-memory dict-like types
|
|
|
|
|
1601
|
if isinstance(obj, dict) or\
|
|
|
|
|
1602
|
_safe_isinstance(obj, 'pandas', 'DataFrame'):
|
|
|
|
|
1603
|
try:
|
|
|
|
|
1604
|
return list(obj.keys())
|
|
|
|
|
1605
|
except Exception:
|
|
|
|
|
1606
|
return []
|
|
|
|
|
1607
|
elif _safe_isinstance(obj, 'numpy', 'ndarray') or\
|
|
|
|
|
1608
|
_safe_isinstance(obj, 'numpy', 'void'):
|
|
|
|
|
1609
|
return obj.dtype.names or []
|
|
|
|
|
1610
|
return []
|
|
|
|
|
1611
|
|
|
1633
|
|
|
1612
|
try:
|
|
1634
|
|
|
|
|
|
1635
|
if self.__dict_key_regexps is not None:
|
|
1613
|
regexps = self.__dict_key_regexps
|
|
1636
|
regexps = self.__dict_key_regexps
|
|
1614
|
except AttributeError:
|
|
1637
|
else:
|
|
1615
|
dict_key_re_fmt = r'''(?x)
|
|
1638
|
dict_key_re_fmt = r'''(?x)
|
|
1616
|
( # match dict-referring expression wrt greedy setting
|
|
1639
|
( # match dict-referring expression wrt greedy setting
|
|
1617
|
%s
|
|
1640
|
%s
|
|
@@
-1651,7
+1674,7
b' class IPCompleter(Completer):'
|
|
1651
|
except Exception:
|
|
1674
|
except Exception:
|
|
1652
|
return []
|
|
1675
|
return []
|
|
1653
|
|
|
1676
|
|
|
1654
|
keys = get_keys(obj)
|
|
1677
|
keys = self._get_keys(obj)
|
|
1655
|
if not keys:
|
|
1678
|
if not keys:
|
|
1656
|
return keys
|
|
1679
|
return keys
|
|
1657
|
closing_quote, token_offset, matches = match_dict_keys(keys, prefix, self.splitter.delims)
|
|
1680
|
closing_quote, token_offset, matches = match_dict_keys(keys, prefix, self.splitter.delims)
|
|
@@
-1696,16
+1719,15
b' class IPCompleter(Completer):'
|
|
1696
|
|
|
1719
|
|
|
1697
|
return [leading + k + suf for k in matches]
|
|
1720
|
return [leading + k + suf for k in matches]
|
|
1698
|
|
|
1721
|
|
|
1699
|
def unicode_name_matches(self, text):
|
|
1722
|
@staticmethod
|
|
1700
|
u"""Match Latex-like syntax for unicode characters base
|
|
1723
|
def unicode_name_matches(text:str) -> Tuple[str, List[str]] :
|
|
|
|
|
1724
|
"""Match Latex-like syntax for unicode characters base
|
|
1701
|
on the name of the character.
|
|
1725
|
on the name of the character.
|
|
1702
|
|
|
1726
|
|
|
1703
|
This does ``\\GREEK SMALL LETTER ETA`` -> ``η``
|
|
1727
|
This does ``\\GREEK SMALL LETTER ETA`` -> ``η``
|
|
1704
|
|
|
1728
|
|
|
1705
|
Works only on valid python 3 identifier, or on combining characters that
|
|
1729
|
Works only on valid python 3 identifier, or on combining characters that
|
|
1706
|
will combine to form a valid identifier.
|
|
1730
|
will combine to form a valid identifier.
|
|
1707
|
|
|
|
|
|
1708
|
Used on Python 3 only.
|
|
|
|
|
1709
|
"""
|
|
1731
|
"""
|
|
1710
|
slashpos = text.rfind('\\')
|
|
1732
|
slashpos = text.rfind('\\')
|
|
1711
|
if slashpos > -1:
|
|
1733
|
if slashpos > -1:
|
|
@@
-1717,11
+1739,11
b' class IPCompleter(Completer):'
|
|
1717
|
return '\\'+s,[unic]
|
|
1739
|
return '\\'+s,[unic]
|
|
1718
|
except KeyError:
|
|
1740
|
except KeyError:
|
|
1719
|
pass
|
|
1741
|
pass
|
|
1720
|
return u'', []
|
|
1742
|
return '', []
|
|
1721
|
|
|
1743
|
|
|
1722
|
|
|
1744
|
|
|
1723
|
def latex_matches(self, text):
|
|
1745
|
def latex_matches(self, text:str) -> Tuple[str, Sequence[str]]:
|
|
1724
|
u"""Match Latex syntax for unicode characters.
|
|
1746
|
"""Match Latex syntax for unicode characters.
|
|
1725
|
|
|
1747
|
|
|
1726
|
This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``α``
|
|
1748
|
This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``α``
|
|
1727
|
"""
|
|
1749
|
"""
|
|
@@
-1738,7
+1760,7
b' class IPCompleter(Completer):'
|
|
1738
|
matches = [k for k in latex_symbols if k.startswith(s)]
|
|
1760
|
matches = [k for k in latex_symbols if k.startswith(s)]
|
|
1739
|
if matches:
|
|
1761
|
if matches:
|
|
1740
|
return s, matches
|
|
1762
|
return s, matches
|
|
1741
|
return u'', []
|
|
1763
|
return '', ()
|
|
1742
|
|
|
1764
|
|
|
1743
|
def dispatch_custom_completer(self, text):
|
|
1765
|
def dispatch_custom_completer(self, text):
|
|
1744
|
if not self.custom_completers:
|
|
1766
|
if not self.custom_completers:
|
|
@@
-1839,6
+1861,7
b' class IPCompleter(Completer):'
|
|
1839
|
category=ProvisionalCompleterWarning, stacklevel=2)
|
|
1861
|
category=ProvisionalCompleterWarning, stacklevel=2)
|
|
1840
|
|
|
1862
|
|
|
1841
|
seen = set()
|
|
1863
|
seen = set()
|
|
|
|
|
1864
|
profiler:Optional[cProfile.Profile]
|
|
1842
|
try:
|
|
1865
|
try:
|
|
1843
|
if self.profile_completions:
|
|
1866
|
if self.profile_completions:
|
|
1844
|
import cProfile
|
|
1867
|
import cProfile
|
|
@@
-1864,7
+1887,7
b' class IPCompleter(Completer):'
|
|
1864
|
print("Writing profiler output to", output_path)
|
|
1887
|
print("Writing profiler output to", output_path)
|
|
1865
|
profiler.dump_stats(output_path)
|
|
1888
|
profiler.dump_stats(output_path)
|
|
1866
|
|
|
1889
|
|
|
1867
|
def _completions(self, full_text: str, offset: int, *, _timeout)->Iterator[Completion]:
|
|
1890
|
def _completions(self, full_text: str, offset: int, *, _timeout) -> Iterator[Completion]:
|
|
1868
|
"""
|
|
1891
|
"""
|
|
1869
|
Core completion module.Same signature as :any:`completions`, with the
|
|
1892
|
Core completion module.Same signature as :any:`completions`, with the
|
|
1870
|
extra `timeout` parameter (in seconds).
|
|
1893
|
extra `timeout` parameter (in seconds).
|
|
@@
-1949,7
+1972,7
b' class IPCompleter(Completer):'
|
|
1949
|
yield Completion(start=start_offset, end=offset, text=m, _origin=t, signature='', type='<unknown>')
|
|
1972
|
yield Completion(start=start_offset, end=offset, text=m, _origin=t, signature='', type='<unknown>')
|
|
1950
|
|
|
1973
|
|
|
1951
|
|
|
1974
|
|
|
1952
|
def complete(self, text=None, line_buffer=None, cursor_pos=None):
|
|
1975
|
def complete(self, text=None, line_buffer=None, cursor_pos=None) -> Tuple[str, Sequence[str]]:
|
|
1953
|
"""Find completions for the given text and line context.
|
|
1976
|
"""Find completions for the given text and line context.
|
|
1954
|
|
|
1977
|
|
|
1955
|
Note that both the text and the line_buffer are optional, but at least
|
|
1978
|
Note that both the text and the line_buffer are optional, but at least
|
|
@@
-1973,9
+1996,9
b' class IPCompleter(Completer):'
|
|
1973
|
|
|
1996
|
|
|
1974
|
Returns
|
|
1997
|
Returns
|
|
1975
|
-------
|
|
1998
|
-------
|
|
|
|
|
1999
|
Tuple of two items:
|
|
1976
|
text : str
|
|
2000
|
text : str
|
|
1977
|
Text that was actually used in the completion.
|
|
2001
|
Text that was actually used in the completion.
|
|
1978
|
|
|
|
|
|
1979
|
matches : list
|
|
2002
|
matches : list
|
|
1980
|
A list of completion matches.
|
|
2003
|
A list of completion matches.
|
|
1981
|
|
|
2004
|
|
|
@@
-1995,7
+2018,7
b' class IPCompleter(Completer):'
|
|
1995
|
return self._complete(line_buffer=line_buffer, cursor_pos=cursor_pos, text=text, cursor_line=0)[:2]
|
|
2018
|
return self._complete(line_buffer=line_buffer, cursor_pos=cursor_pos, text=text, cursor_line=0)[:2]
|
|
1996
|
|
|
2019
|
|
|
1997
|
def _complete(self, *, cursor_line, cursor_pos, line_buffer=None, text=None,
|
|
2020
|
def _complete(self, *, cursor_line, cursor_pos, line_buffer=None, text=None,
|
|
1998
|
full_text=None) -> Tuple[str, List[str], List[str], Iterable[_FakeJediCompletion]]:
|
|
2021
|
full_text=None) -> _CompleteResult:
|
|
1999
|
"""
|
|
2022
|
"""
|
|
2000
|
|
|
2023
|
|
|
2001
|
Like complete but can also returns raw jedi completions as well as the
|
|
2024
|
Like complete but can also returns raw jedi completions as well as the
|
|
@@
-2008,8
+2031,19
b' class IPCompleter(Completer):'
|
|
2008
|
caller) as the offset in the ``text`` or ``line_buffer``, or as the
|
|
2031
|
caller) as the offset in the ``text`` or ``line_buffer``, or as the
|
|
2009
|
``column`` when passing multiline strings this could/should be renamed
|
|
2032
|
``column`` when passing multiline strings this could/should be renamed
|
|
2010
|
but would add extra noise.
|
|
2033
|
but would add extra noise.
|
|
|
|
|
2034
|
|
|
|
|
|
2035
|
Return
|
|
|
|
|
2036
|
======
|
|
|
|
|
2037
|
|
|
|
|
|
2038
|
A tuple of N elements which are (likely):
|
|
|
|
|
2039
|
|
|
|
|
|
2040
|
matched_text: ? the text that the complete matched
|
|
|
|
|
2041
|
matches: list of completions ?
|
|
|
|
|
2042
|
matches_origin: ? list same lenght as matches, and where each completion came from
|
|
|
|
|
2043
|
jedi_matches: list of Jedi matches, have it's own structure.
|
|
2011
|
"""
|
|
2044
|
"""
|
|
2012
|
|
|
2045
|
|
|
|
|
|
2046
|
|
|
2013
|
# if the cursor position isn't given, the only sane assumption we can
|
|
2047
|
# if the cursor position isn't given, the only sane assumption we can
|
|
2014
|
# make is that it's at the end of the line (the common case)
|
|
2048
|
# make is that it's at the end of the line (the common case)
|
|
2015
|
if cursor_pos is None:
|
|
2049
|
if cursor_pos is None:
|
|
@@
-2027,17
+2061,16
b' class IPCompleter(Completer):'
|
|
2027
|
if self.backslash_combining_completions:
|
|
2061
|
if self.backslash_combining_completions:
|
|
2028
|
# allow deactivation of these on windows.
|
|
2062
|
# allow deactivation of these on windows.
|
|
2029
|
base_text = text if not line_buffer else line_buffer[:cursor_pos]
|
|
2063
|
base_text = text if not line_buffer else line_buffer[:cursor_pos]
|
|
2030
|
latex_text, latex_matches = self.latex_matches(base_text)
|
|
2064
|
|
|
2031
|
if latex_matches:
|
|
2065
|
for meth in (self.latex_matches,
|
|
2032
|
return latex_text, latex_matches, ['latex_matches']*len(latex_matches), ()
|
|
2066
|
self.unicode_name_matches,
|
|
2033
|
name_text = ''
|
|
2067
|
back_latex_name_matches,
|
|
2034
|
name_matches = []
|
|
2068
|
back_unicode_name_matches,
|
|
2035
|
# need to add self.fwd_unicode_match() function here when done
|
|
2069
|
self.fwd_unicode_match):
|
|
2036
|
for meth in (self.unicode_name_matches, back_latex_name_matches, back_unicode_name_matches, self.fwd_unicode_match):
|
|
|
|
|
2037
|
name_text, name_matches = meth(base_text)
|
|
2070
|
name_text, name_matches = meth(base_text)
|
|
2038
|
if name_text:
|
|
2071
|
if name_text:
|
|
2039
|
return name_text, name_matches[:MATCHES_LIMIT], \
|
|
2072
|
return _CompleteResult(name_text, name_matches[:MATCHES_LIMIT], \
|
|
2040
|
[meth.__qualname__]*min(len(name_matches), MATCHES_LIMIT), ()
|
|
2073
|
[meth.__qualname__]*min(len(name_matches), MATCHES_LIMIT), ())
|
|
2041
|
|
|
2074
|
|
|
2042
|
|
|
2075
|
|
|
2043
|
# If no line buffer is given, assume the input text is all there was
|
|
2076
|
# If no line buffer is given, assume the input text is all there was
|
|
@@
-2052,7
+2085,7
b' class IPCompleter(Completer):'
|
|
2052
|
matches = list(matcher(line_buffer))[:MATCHES_LIMIT]
|
|
2085
|
matches = list(matcher(line_buffer))[:MATCHES_LIMIT]
|
|
2053
|
if matches:
|
|
2086
|
if matches:
|
|
2054
|
origins = [matcher.__qualname__] * len(matches)
|
|
2087
|
origins = [matcher.__qualname__] * len(matches)
|
|
2055
|
return text, matches, origins, ()
|
|
2088
|
return _CompleteResult(text, matches, origins, ())
|
|
2056
|
|
|
2089
|
|
|
2057
|
# Start with a clean slate of completions
|
|
2090
|
# Start with a clean slate of completions
|
|
2058
|
matches = []
|
|
2091
|
matches = []
|
|
@@
-2061,13
+2094,13
b' class IPCompleter(Completer):'
|
|
2061
|
# different types of objects. The rlcomplete() method could then
|
|
2094
|
# different types of objects. The rlcomplete() method could then
|
|
2062
|
# simply collapse the dict into a list for readline, but we'd have
|
|
2095
|
# simply collapse the dict into a list for readline, but we'd have
|
|
2063
|
# richer completion semantics in other environments.
|
|
2096
|
# richer completion semantics in other environments.
|
|
2064
|
completions = ()
|
|
2097
|
completions:Iterable[Any] = []
|
|
2065
|
if self.use_jedi:
|
|
2098
|
if self.use_jedi:
|
|
2066
|
if not full_text:
|
|
2099
|
if not full_text:
|
|
2067
|
full_text = line_buffer
|
|
2100
|
full_text = line_buffer
|
|
2068
|
completions = self._jedi_matches(
|
|
2101
|
completions = self._jedi_matches(
|
|
2069
|
cursor_pos, cursor_line, full_text)
|
|
2102
|
cursor_pos, cursor_line, full_text)
|
|
2070
|
|
|
2103
|
|
|
2071
|
if self.merge_completions:
|
|
2104
|
if self.merge_completions:
|
|
2072
|
matches = []
|
|
2105
|
matches = []
|
|
2073
|
for matcher in self.matchers:
|
|
2106
|
for matcher in self.matchers:
|
|
@@
-2105,9
+2138,38
b' class IPCompleter(Completer):'
|
|
2105
|
|
|
2138
|
|
|
2106
|
self.matches = _matches
|
|
2139
|
self.matches = _matches
|
|
2107
|
|
|
2140
|
|
|
2108
|
return text, _matches, origins, completions
|
|
2141
|
return _CompleteResult(text, _matches, origins, completions)
|
|
2109
|
|
|
2142
|
|
|
2110
|
def fwd_unicode_match(self, text:str) -> Tuple[str, list]:
|
|
2143
|
def fwd_unicode_match(self, text:str) -> Tuple[str, Sequence[str]]:
|
|
|
|
|
2144
|
"""
|
|
|
|
|
2145
|
|
|
|
|
|
2146
|
Forward match a string starting with a backslash with a list of
|
|
|
|
|
2147
|
potential Unicode completions.
|
|
|
|
|
2148
|
|
|
|
|
|
2149
|
Will compute list list of Unicode character names on first call and cache it.
|
|
|
|
|
2150
|
|
|
|
|
|
2151
|
Return
|
|
|
|
|
2152
|
======
|
|
|
|
|
2153
|
|
|
|
|
|
2154
|
At tuple with:
|
|
|
|
|
2155
|
- matched text (empty if no matches)
|
|
|
|
|
2156
|
- list of potential completions, empty tuple otherwise)
|
|
|
|
|
2157
|
"""
|
|
|
|
|
2158
|
# TODO: self.unicode_names is here a list we traverse each time with ~100k elements.
|
|
|
|
|
2159
|
# We could do a faster match using a Trie.
|
|
|
|
|
2160
|
|
|
|
|
|
2161
|
# Using pygtrie the follwing seem to work:
|
|
|
|
|
2162
|
|
|
|
|
|
2163
|
# s = PrefixSet()
|
|
|
|
|
2164
|
|
|
|
|
|
2165
|
# for c in range(0,0x10FFFF + 1):
|
|
|
|
|
2166
|
# try:
|
|
|
|
|
2167
|
# s.add(unicodedata.name(chr(c)))
|
|
|
|
|
2168
|
# except ValueError:
|
|
|
|
|
2169
|
# pass
|
|
|
|
|
2170
|
# [''.join(k) for k in s.iter(prefix)]
|
|
|
|
|
2171
|
|
|
|
|
|
2172
|
# But need to be timed and adds an extra dependency.
|
|
2111
|
|
|
2173
|
|
|
2112
|
slashpos = text.rfind('\\')
|
|
2174
|
slashpos = text.rfind('\\')
|
|
2113
|
# if text starts with slash
|
|
2175
|
# if text starts with slash
|
|
@@
-2126,7
+2188,7
b' class IPCompleter(Completer):'
|
|
2126
|
|
|
2188
|
|
|
2127
|
# if text does not start with slash
|
|
2189
|
# if text does not start with slash
|
|
2128
|
else:
|
|
2190
|
else:
|
|
2129
|
return u'', ()
|
|
2191
|
return '', ()
|
|
2130
|
|
|
2192
|
|
|
2131
|
@property
|
|
2193
|
@property
|
|
2132
|
def unicode_names(self) -> List[str]:
|
|
2194
|
def unicode_names(self) -> List[str]:
|
|
@@
-2141,6
+2203,16
b' class IPCompleter(Completer):'
|
|
2141
|
names.append(unicodedata.name(chr(c)))
|
|
2203
|
names.append(unicodedata.name(chr(c)))
|
|
2142
|
except ValueError:
|
|
2204
|
except ValueError:
|
|
2143
|
pass
|
|
2205
|
pass
|
|
2144
|
self._unicode_names = names
|
|
2206
|
self._unicode_names = _unicode_name_compute(_UNICODE_RANGES)
|
|
2145
|
|
|
2207
|
|
|
2146
|
return self._unicode_names
|
|
2208
|
return self._unicode_names
|
|
|
|
|
2209
|
|
|
|
|
|
2210
|
def _unicode_name_compute(ranges:List[Tuple[int,int]]) -> List[str]:
|
|
|
|
|
2211
|
names = []
|
|
|
|
|
2212
|
for start,stop in ranges:
|
|
|
|
|
2213
|
for c in range(start, stop) :
|
|
|
|
|
2214
|
try:
|
|
|
|
|
2215
|
names.append(unicodedata.name(chr(c)))
|
|
|
|
|
2216
|
except ValueError:
|
|
|
|
|
2217
|
pass
|
|
|
|
|
2218
|
return names
|