Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitdce92c6

Browse files
committed
Rewrite tab completion's previous-word fetching for more sanity.
Make it return empty strings when there are no more words to the left ofthe current position, instead of sometimes returning NULL and other timesreturning copies of the leftmost word. Also, fetch the words in one scan,rather than the previous wasteful approach of starting from scratch foreach word. Make the code a bit harder to break when someone decides weneed more words of context, too. (There was actually a memory leak here,because whoever added prev6_wd neglected to free it.)
1 parent8f3362d commitdce92c6

File tree

1 file changed

+76
-66
lines changed

1 file changed

+76
-66
lines changed

‎src/bin/psql/tab-complete.c

Lines changed: 76 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ static char **complete_from_variables(char *text,
668668

669669
staticPGresult*exec_query(constchar*query);
670670

671-
staticchar*previous_word(intpoint,intskip);
671+
staticvoidget_previous_words(intpoint,char**previous_words,intnwords);
672672

673673
#ifdefNOT_USED
674674
staticchar*quote_file_name(char*text,intmatch_type,char*quote_pointer);
@@ -710,13 +710,16 @@ psql_completion(char *text, int start, int end)
710710
/* This is the variable we'll return. */
711711
char**matches=NULL;
712712

713-
/* These are going to contain some scannage of the input line. */
714-
char*prev_wd,
715-
*prev2_wd,
716-
*prev3_wd,
717-
*prev4_wd,
718-
*prev5_wd,
719-
*prev6_wd;
713+
/* This array will contain some scannage of the input line. */
714+
char*previous_words[6];
715+
716+
/* For compactness, we use these macros to reference previous_words[]. */
717+
#defineprev_wd (previous_words[0])
718+
#defineprev2_wd (previous_words[1])
719+
#defineprev3_wd (previous_words[2])
720+
#defineprev4_wd (previous_words[3])
721+
#defineprev5_wd (previous_words[4])
722+
#defineprev6_wd (previous_words[5])
720723

721724
staticconstchar*constsql_commands[]= {
722725
"ABORT","ALTER","ANALYZE","BEGIN","CHECKPOINT","CLOSE","CLUSTER",
@@ -755,16 +758,11 @@ psql_completion(char *text, int start, int end)
755758
completion_info_charp2=NULL;
756759

757760
/*
758-
* Scan the input line before our current position for the lastfive
761+
* Scan the input line before our current position for the lastfew
759762
* words. According to those we'll make some smart decisions on what the
760-
* user is probably intending to type. TODO: Use strtokx() to do this.
763+
* user is probably intending to type.
761764
*/
762-
prev_wd=previous_word(start,0);
763-
prev2_wd=previous_word(start,1);
764-
prev3_wd=previous_word(start,2);
765-
prev4_wd=previous_word(start,3);
766-
prev5_wd=previous_word(start,4);
767-
prev6_wd=previous_word(start,5);
765+
get_previous_words(start,previous_words,lengthof(previous_words));
768766

769767
/* If a backslash command was started, continue */
770768
if (text[0]=='\\')
@@ -782,18 +780,18 @@ psql_completion(char *text, int start, int end)
782780
}
783781

784782
/* If no previous word, suggest one of the basic sql commands */
785-
elseif (!prev_wd)
783+
elseif (prev_wd[0]=='\0')
786784
COMPLETE_WITH_LIST(sql_commands);
787785

788786
/* CREATE */
789787
/* complete with something you can create */
790788
elseif (pg_strcasecmp(prev_wd,"CREATE")==0)
791789
matches=completion_matches(text,create_command_generator);
792790

793-
/* DROP, butwatch out for DROP embedded in other commands */
791+
/* DROP, butnot DROP embedded in other commands */
794792
/* complete with something you can drop */
795793
elseif (pg_strcasecmp(prev_wd,"DROP")==0&&
796-
pg_strcasecmp(prev2_wd,"DROP")==0)
794+
prev2_wd[0]=='\0')
797795
matches=completion_matches(text,drop_command_generator);
798796

799797
/* ALTER */
@@ -2918,11 +2916,12 @@ psql_completion(char *text, int start, int end)
29182916
}
29192917

29202918
/* free storage */
2921-
free(prev_wd);
2922-
free(prev2_wd);
2923-
free(prev3_wd);
2924-
free(prev4_wd);
2925-
free(prev5_wd);
2919+
{
2920+
inti;
2921+
2922+
for (i=0;i<lengthof(previous_words);i++)
2923+
free(previous_words[i]);
2924+
}
29262925

29272926
/* Return our Grand List O' Matches */
29282927
returnmatches;
@@ -3372,77 +3371,88 @@ exec_query(const char *query)
33723371

33733372

33743373
/*
3375-
* Return the word (space delimited) before point. Set skip > 0 to
3376-
* skip that many words; e.g. skip=1 finds the word before the
3377-
* previous one. Return value is NULL or a malloc'ed string.
3374+
* Return the nwords word(s) before point. Words are returned right to left,
3375+
* that is, previous_words[0] gets the last word before point.
3376+
* If we run out of words, remaining array elements are set to empty strings.
3377+
* Each array element is filled with a malloc'd string.
33783378
*/
3379-
staticchar*
3380-
previous_word(intpoint,intskip)
3379+
staticvoid
3380+
get_previous_words(intpoint,char**previous_words,intnwords)
33813381
{
3382-
inti,
3383-
start=0,
3384-
end=-1,
3385-
inquotes=0;
3386-
char*s;
33873382
constchar*buf=rl_line_buffer;/* alias */
3383+
inti;
33883384

3389-
/* first we look for aspace or a parenthesisbefore the currentword */
3385+
/* first we look for anon-word charbefore the currentpoint */
33903386
for (i=point-1;i >=0;i--)
33913387
if (strchr(WORD_BREAKS,buf[i]))
33923388
break;
33933389
point=i;
33943390

3395-
while (skip-- >=0)
3391+
while (nwords-->0)
33963392
{
3397-
intparentheses=0;
3393+
intstart,
3394+
end;
3395+
char*s;
33983396

33993397
/* now find the first non-space which then constitutes the end */
3398+
end=-1;
34003399
for (i=point;i >=0;i--)
3401-
if (buf[i]!=' ')
3400+
{
3401+
if (!isspace((unsignedchar)buf[i]))
34023402
{
34033403
end=i;
34043404
break;
34053405
}
3406+
}
34063407

34073408
/*
3408-
* If no end found we return null, because there is no word before the
3409-
* point
3410-
*/
3411-
if (end==-1)
3412-
returnNULL;
3413-
3414-
/*
3415-
* Otherwise we now look for the start. The start is either the last
3416-
* character before any space going backwards from the end, or it's
3417-
* simply character 0. We also handle open quotes and parentheses.
3409+
* If no end found we return an empty string, because there is no word
3410+
* before the point
34183411
*/
3419-
for (start=end;start>0;start--)
3412+
if (end<0)
3413+
{
3414+
point=end;
3415+
s=pg_strdup("");
3416+
}
3417+
else
34203418
{
3421-
if (buf[start]=='"')
3422-
inquotes= !inquotes;
3423-
if (inquotes==0)
3419+
/*
3420+
* Otherwise we now look for the start. The start is either the
3421+
* last character before any word-break character going backwards
3422+
* from the end, or it's simply character 0. We also handle open
3423+
* quotes and parentheses.
3424+
*/
3425+
boolinquotes= false;
3426+
intparentheses=0;
3427+
3428+
for (start=end;start>0;start--)
34243429
{
3425-
if (buf[start]==')')
3426-
parentheses++;
3427-
elseif (buf[start]=='(')
3430+
if (buf[start]=='"')
3431+
inquotes= !inquotes;
3432+
elseif (!inquotes)
34283433
{
3429-
if (--parentheses <=0)
3434+
if (buf[start]==')')
3435+
parentheses++;
3436+
elseif (buf[start]=='(')
3437+
{
3438+
if (--parentheses <=0)
3439+
break;
3440+
}
3441+
elseif (parentheses==0&&
3442+
strchr(WORD_BREAKS,buf[start-1]))
34303443
break;
34313444
}
3432-
elseif (parentheses==0&&
3433-
strchr(WORD_BREAKS,buf[start-1]))
3434-
break;
34353445
}
3436-
}
34373446

3438-
point=start-1;
3439-
}
3447+
point=start-1;
34403448

3441-
/* make a copy */
3442-
s=pg_malloc(end-start+2);
3443-
strlcpy(s,&buf[start],end-start+2);
3449+
/* make a copy of chars from start to end inclusive */
3450+
s=pg_malloc(end-start+2);
3451+
strlcpy(s,&buf[start],end-start+2);
3452+
}
34443453

3445-
returns;
3454+
*previous_words++=s;
3455+
}
34463456
}
34473457

34483458
#ifdefNOT_USED

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp