1111from pygments .lexers ._mysql_builtins import MYSQL_DATATYPES , MYSQL_FUNCTIONS , MYSQL_KEYWORDS
1212import rapidfuzz
1313
14- from mycli .packages .completion_engine import suggest_type
14+ from mycli .packages .completion_engine import is_inside_quotes , suggest_type
1515from mycli .packages .filepaths import complete_path , parse_path , suggest_path
1616from mycli .packages .parseutils import extract_columns_from_select , last_word
1717from mycli .packages .special import llm
@@ -810,13 +810,6 @@ def escape_name(self, name: str) -> str:
810810
811811 return name
812812
813- def unescape_name (self , name : str ) -> str :
814- """Unquote a string."""
815- if name and name [0 ] == '"' and name [- 1 ] == '"' :
816- name = name [1 :- 1 ]
817-
818- return name
819-
820813 def escaped_names (self , names : Collection [str ]) -> list [str ]:
821814 return [self .escape_name (name ) for name in names ]
822815
@@ -974,6 +967,7 @@ def find_matches(
974967 start_only : bool = False ,
975968 fuzzy : bool = True ,
976969 casing : str | None = None ,
970+ text_before_cursor : str = '' ,
977971 ) -> Generator [tuple [str , int ], None , None ]:
978972 """Find completion matches for the given text.
979973
@@ -995,13 +989,26 @@ def find_matches(
995989
996990 completions : list [tuple [str , int ]] = []
997991
992+ def maybe_quote_identifier (item : str ) -> str :
993+ if item .startswith ('`' ):
994+ return item
995+ if item == '*' :
996+ return item
997+ return '`' + item + '`'
998+
999+ # checking text.startswith() first is an optimization; is_inside_quotes() covers more cases
1000+ if text .startswith ('`' ) or is_inside_quotes (text_before_cursor , len (text_before_cursor )) == 'backtick' :
1001+ quoted_collection : Collection [Any ] = [maybe_quote_identifier (x ) if isinstance (x , str ) else x for x in collection ]
1002+ else :
1003+ quoted_collection = collection
1004+
9981005 if fuzzy :
9991006 regex = ".{0,3}?" .join (map (re .escape , text ))
10001007 pat = re .compile (f'({ regex } )' )
10011008 under_words_text = [x for x in text .split ('_' ) if x ]
10021009 case_words_text = re .split (case_change_pat , last )
10031010
1004- for item in collection :
1011+ for item in quoted_collection :
10051012 r = pat .search (item .lower ())
10061013 if r :
10071014 completions .append ((item , Fuzziness .REGEX ))
@@ -1032,7 +1039,7 @@ def find_matches(
10321039 if len (text ) >= 4 :
10331040 rapidfuzz_matches = rapidfuzz .process .extract (
10341041 text ,
1035- collection ,
1042+ quoted_collection ,
10361043 scorer = rapidfuzz .fuzz .WRatio ,
10371044 # todo: maybe make our own processor which only does case-folding
10381045 # because underscores are valuable info
@@ -1050,7 +1057,7 @@ def find_matches(
10501057
10511058 else :
10521059 match_end_limit = len (text ) if start_only else None
1053- for item in collection :
1060+ for item in quoted_collection :
10541061 match_point = item .lower ().find (text , 0 , match_end_limit )
10551062 if match_point >= 0 :
10561063 completions .append ((item , Fuzziness .PERFECT ))
@@ -1083,7 +1090,13 @@ def get_completions(
10831090 # If smart_completion is off then match any word that starts with
10841091 # 'word_before_cursor'.
10851092 if not smart_completion :
1086- matches = self .find_matches (word_before_cursor , self .all_completions , start_only = True , fuzzy = False )
1093+ matches = self .find_matches (
1094+ word_before_cursor ,
1095+ self .all_completions ,
1096+ start_only = True ,
1097+ fuzzy = False ,
1098+ text_before_cursor = document .text_before_cursor ,
1099+ )
10871100 return (Completion (x [0 ], - len (text_for_len )) for x in matches )
10881101
10891102 completions : list [tuple [str , int , int ]] = []
@@ -1110,13 +1123,21 @@ def get_completions(
11101123 # showing all columns. So make them unique and sort them.
11111124 scoped_cols = sorted (set (scoped_cols ), key = lambda s : s .strip ('`' ))
11121125
1113- cols = self .find_matches (word_before_cursor , scoped_cols )
1126+ cols = self .find_matches (
1127+ word_before_cursor ,
1128+ scoped_cols ,
1129+ text_before_cursor = document .text_before_cursor ,
1130+ )
11141131 completions .extend ([(* x , rank ) for x in cols ])
11151132
11161133 elif suggestion ["type" ] == "function" :
11171134 # suggest user-defined functions using substring matching
11181135 funcs = self .populate_schema_objects (suggestion ["schema" ], "functions" )
1119- user_funcs = self .find_matches (word_before_cursor , funcs )
1136+ user_funcs = self .find_matches (
1137+ word_before_cursor ,
1138+ funcs ,
1139+ text_before_cursor = document .text_before_cursor ,
1140+ )
11201141 completions .extend ([(* x , rank ) for x in user_funcs ])
11211142
11221143 # suggest hardcoded functions using startswith matching only if
@@ -1125,13 +1146,22 @@ def get_completions(
11251146 # eg: SELECT * FROM users u WHERE u.
11261147 if not suggestion ["schema" ]:
11271148 predefined_funcs = self .find_matches (
1128- word_before_cursor , self .functions , start_only = True , fuzzy = False , casing = self .keyword_casing
1149+ word_before_cursor ,
1150+ self .functions ,
1151+ start_only = True ,
1152+ fuzzy = False ,
1153+ casing = self .keyword_casing ,
1154+ text_before_cursor = document .text_before_cursor ,
11291155 )
11301156 completions .extend ([(* x , rank ) for x in predefined_funcs ])
11311157
11321158 elif suggestion ["type" ] == "procedure" :
11331159 procs = self .populate_schema_objects (suggestion ["schema" ], "procedures" )
1134- procs_m = self .find_matches (word_before_cursor , procs )
1160+ procs_m = self .find_matches (
1161+ word_before_cursor ,
1162+ procs ,
1163+ text_before_cursor = document .text_before_cursor ,
1164+ )
11351165 completions .extend ([(* x , rank ) for x in procs_m ])
11361166
11371167 elif suggestion ["type" ] == "table" :
@@ -1144,53 +1174,107 @@ def get_completions(
11441174 tables = self .populate_schema_objects (suggestion ["schema" ], "tables" , columns )
11451175 else :
11461176 tables = self .populate_schema_objects (suggestion ["schema" ], "tables" )
1147- tables_m = self .find_matches (word_before_cursor , tables )
1177+ tables_m = self .find_matches (
1178+ word_before_cursor ,
1179+ tables ,
1180+ text_before_cursor = document .text_before_cursor ,
1181+ )
11481182 completions .extend ([(* x , rank ) for x in tables_m ])
11491183
11501184 elif suggestion ["type" ] == "view" :
11511185 views = self .populate_schema_objects (suggestion ["schema" ], "views" )
1152- views_m = self .find_matches (word_before_cursor , views )
1186+ views_m = self .find_matches (
1187+ word_before_cursor ,
1188+ views ,
1189+ text_before_cursor = document .text_before_cursor ,
1190+ )
11531191 completions .extend ([(* x , rank ) for x in views_m ])
11541192
11551193 elif suggestion ["type" ] == "alias" :
11561194 aliases = suggestion ["aliases" ]
1157- aliases_m = self .find_matches (word_before_cursor , aliases )
1195+ aliases_m = self .find_matches (
1196+ word_before_cursor ,
1197+ aliases ,
1198+ text_before_cursor = document .text_before_cursor ,
1199+ )
11581200 completions .extend ([(* x , rank ) for x in aliases_m ])
11591201
11601202 elif suggestion ["type" ] == "database" :
1161- dbs_m = self .find_matches (word_before_cursor , self .databases )
1203+ dbs_m = self .find_matches (
1204+ word_before_cursor ,
1205+ self .databases ,
1206+ text_before_cursor = document .text_before_cursor ,
1207+ )
11621208 completions .extend ([(* x , rank ) for x in dbs_m ])
11631209
11641210 elif suggestion ["type" ] == "keyword" :
1165- keywords_m = self .find_matches (word_before_cursor , self .keywords , casing = self .keyword_casing )
1211+ keywords_m = self .find_matches (
1212+ word_before_cursor ,
1213+ self .keywords ,
1214+ casing = self .keyword_casing ,
1215+ text_before_cursor = document .text_before_cursor ,
1216+ )
11661217 completions .extend ([(* x , rank ) for x in keywords_m ])
11671218
11681219 elif suggestion ["type" ] == "show" :
11691220 show_items_m = self .find_matches (
1170- word_before_cursor , self .show_items , start_only = False , fuzzy = True , casing = self .keyword_casing
1221+ word_before_cursor ,
1222+ self .show_items ,
1223+ start_only = False ,
1224+ fuzzy = True ,
1225+ casing = self .keyword_casing ,
1226+ text_before_cursor = document .text_before_cursor ,
11711227 )
11721228 completions .extend ([(* x , rank ) for x in show_items_m ])
11731229
11741230 elif suggestion ["type" ] == "change" :
1175- change_items_m = self .find_matches (word_before_cursor , self .change_items , start_only = False , fuzzy = True )
1231+ change_items_m = self .find_matches (
1232+ word_before_cursor ,
1233+ self .change_items ,
1234+ start_only = False ,
1235+ fuzzy = True ,
1236+ text_before_cursor = document .text_before_cursor ,
1237+ )
11761238 completions .extend ([(* x , rank ) for x in change_items_m ])
11771239
11781240 elif suggestion ["type" ] == "user" :
1179- users_m = self .find_matches (word_before_cursor , self .users , start_only = False , fuzzy = True )
1241+ users_m = self .find_matches (
1242+ word_before_cursor ,
1243+ self .users ,
1244+ start_only = False ,
1245+ fuzzy = True ,
1246+ text_before_cursor = document .text_before_cursor ,
1247+ )
11801248 completions .extend ([(* x , rank ) for x in users_m ])
11811249
11821250 elif suggestion ["type" ] == "special" :
1183- special_m = self .find_matches (word_before_cursor , self .special_commands , start_only = True , fuzzy = False )
1251+ special_m = self .find_matches (
1252+ word_before_cursor ,
1253+ self .special_commands ,
1254+ start_only = True ,
1255+ fuzzy = False ,
1256+ text_before_cursor = document .text_before_cursor ,
1257+ )
11841258 # specials are special, and go early in the candidates, first if possible
11851259 completions .extend ([(* x , 0 ) for x in special_m ])
11861260
11871261 elif suggestion ["type" ] == "favoritequery" :
11881262 if hasattr (FavoriteQueries , 'instance' ) and hasattr (FavoriteQueries .instance , 'list' ):
1189- queries_m = self .find_matches (word_before_cursor , FavoriteQueries .instance .list (), start_only = False , fuzzy = True )
1263+ queries_m = self .find_matches (
1264+ word_before_cursor ,
1265+ FavoriteQueries .instance .list (),
1266+ start_only = False ,
1267+ fuzzy = True ,
1268+ text_before_cursor = document .text_before_cursor ,
1269+ )
11901270 completions .extend ([(* x , rank ) for x in queries_m ])
11911271
11921272 elif suggestion ["type" ] == "table_format" :
1193- formats_m = self .find_matches (word_before_cursor , self .table_formats )
1273+ formats_m = self .find_matches (
1274+ word_before_cursor ,
1275+ self .table_formats ,
1276+ text_before_cursor = document .text_before_cursor ,
1277+ )
11941278 completions .extend ([(* x , rank ) for x in formats_m ])
11951279
11961280 elif suggestion ["type" ] == "file_name" :
@@ -1210,6 +1294,7 @@ def get_completions(
12101294 possible_entries ,
12111295 start_only = False ,
12121296 fuzzy = True ,
1297+ text_before_cursor = document .text_before_cursor ,
12131298 )
12141299 completions .extend ([(* x , rank ) for x in subcommands_m ])
12151300 elif suggestion ["type" ] == "enum_value" :
@@ -1220,7 +1305,14 @@ def get_completions(
12201305 )
12211306 if enum_values :
12221307 quoted_values = [self ._quote_sql_string (value ) for value in enum_values ]
1223- completions = [(* x , rank ) for x in self .find_matches (word_before_cursor , quoted_values )]
1308+ completions = [
1309+ (* x , rank )
1310+ for x in self .find_matches (
1311+ word_before_cursor ,
1312+ quoted_values ,
1313+ text_before_cursor = document .text_before_cursor ,
1314+ )
1315+ ]
12241316 break
12251317
12261318 def completion_sort_key (item : tuple [str , int , int ], text_for_len : str ):
0 commit comments