diff --git a/IPython/core/completer.py b/IPython/core/completer.py index d58c2bf..83cd6be 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -61,11 +61,13 @@ import keyword import os import re import sys +import unicodedata +import string -from IPython.config.configurable import Configurable +from IPython.config.configurable import Configurable from IPython.core.error import TryNext from IPython.core.inputsplitter import ESC_MAGIC -from IPython.core.latex_symbols import latex_symbols +from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol from IPython.utils import generics from IPython.utils import io from IPython.utils.decorators import undoc @@ -955,6 +957,88 @@ class IPCompleter(Completer): return [leading + k + suf for k in matches] + def unicode_name_matches(self, text): + u"""Match Latex-like syntax for unicode characters base + on the name of the character. + + This does \\GREEK SMALL LETTER ETA -> η + + Works only on valid python 3 identifier, or on combining characters that + will combine to form a valid identifier. + + Used on Python 3 only. + """ + slashpos = text.rfind('\\') + if slashpos > -1: + s = text[slashpos+1:] + try : + unic = unicodedata.lookup(s) + # allow combining chars + if ('a'+unic).isidentifier(): + return '\\'+s,[unic] + except KeyError as e: + pass + return u'', [] + + def back_unicode_name_matches(self, text): + u"""Match unicode characters back to unicode name + + This does ☃ -> \\snowman + + Note that snowman is not a valid python3 combining character but will be expanded. + Though it will not recombine back to the snowman character by the completion machinery. + + This will not either back-complete standard sequences like \n, \b ... + + Used on Python 3 only. + """ + if len(text)<2: + return u'', () + maybe_slash = text[-2] + if maybe_slash != '\\': + return u'', () + + char = text[-1] + # no expand on quote for completion in strings. + # nor backcomplete standard ascii keys + if char in string.ascii_letters or char in ['"',"'"]: + return u'', () + try : + unic = unicodedata.name(char) + return '\\'+char,['\\'+unic] + except KeyError as e: + pass + return u'', () + + def back_latex_name_matches(self, text): + u"""Match latex characters back to unicode name + + This does ->\\sqrt + + Used on Python 3 only. + """ + if len(text)<2: + return u'', () + maybe_slash = text[-2] + if maybe_slash != '\\': + return u'', () + + + char = text[-1] + # no expand on quote for completion in strings. + # nor backcomplete standard ascii keys + if char in string.ascii_letters or char in ['"',"'"]: + return u'', () + try : + latex = reverse_latex_symbol[char] + # '\\' replace the \ as well + return '\\'+char,[latex] + except KeyError as e: + pass + return u'', () + + + def latex_matches(self, text): u"""Match Latex syntax for unicode characters. @@ -1057,11 +1141,21 @@ class IPCompleter(Completer): cursor_pos = len(line_buffer) if text is None else len(text) if PY3: - latex_text = text if not line_buffer else line_buffer[:cursor_pos] - latex_text, latex_matches = self.latex_matches(latex_text) - if latex_matches: - return latex_text, latex_matches + base_text = text if not line_buffer else line_buffer[:cursor_pos] + latex_text, latex_matches = self.latex_matches(base_text) + if latex_matches: + return latex_text, latex_matches + name_text = '' + name_matches = [] + for meth in (self.unicode_name_matches, self.back_unicode_name_matches, self.back_latex_name_matches): + _name_text, _name_matches = meth(base_text) + if _name_text: + name_text = _name_text + name_matches.extend(_name_matches) + if name_text: + return name_text, name_matches + # if text is either None or an empty string, rely on the line buffer if not text: text = self.splitter.split_line(line_buffer, cursor_pos) @@ -1170,3 +1264,4 @@ class IPCompleter(Completer): return self.matches[state] except IndexError: return None + diff --git a/IPython/core/latex_symbols.py b/IPython/core/latex_symbols.py index 2a920e8..ca7200b 100644 --- a/IPython/core/latex_symbols.py +++ b/IPython/core/latex_symbols.py @@ -1295,3 +1295,6 @@ latex_symbols = { "\\mtteight" : "𝟾", "\\mttnine" : "𝟿", } + + +reverse_latex_symbol = { v:k for k,v in latex_symbols.items()} diff --git a/tools/gen_latex_symbols.py b/tools/gen_latex_symbols.py index 47cb8af..c6f484c 100644 --- a/tools/gen_latex_symbols.py +++ b/tools/gen_latex_symbols.py @@ -76,6 +76,11 @@ for line in valid_idents: s += ' "%s" : "%s",\n' % (line[0], line[1]) s += "}\n" +s += """ + +reverse_latex_symbol = { v:k for k,v in latex_symbols.items()} +""" + fn = os.path.join('..','IPython','core','latex_symbols.py') print("Writing the file: %s" % fn) with open(fn, 'w', encoding='utf-8') as f: