# HG changeset patch # User Bram Moolenaar # Date 1548945906 -3600 # Node ID 2e2f07561f4b79a360f8860557ace13aea3cd5a1 # Parent 8a6b91646ba71c5c3a837f9c00226aeb56618a6b patch 8.1.0862: no verbose version of character classes commit https://github.com/vim/vim/commit/221cd9f4dd866503777b2fffa721c1403716ad63 Author: Bram Moolenaar Date: Thu Jan 31 15:34:40 2019 +0100 patch 8.1.0862: no verbose version of character classes Problem: No verbose version of character classes. Solution: Add [:ident:], [:keyword:] and [:fname:]. (Ozaki Kiichi, closes #1373) diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt --- a/runtime/doc/pattern.txt +++ b/runtime/doc/pattern.txt @@ -1118,6 +1118,9 @@ x A single character, with no special me *[:tab:]* [:tab:] the character *[:escape:]* [:escape:] the character *[:backspace:]* [:backspace:] the character +*[:ident:]* [:ident:] identifier character (same as "\i") +*[:keyword:]* [:keyword:] keyword character (same as "\k") +*[:fname:]* [:fname:] file name character (same as "\f") The brackets in character class expressions are additional to the brackets delimiting a collection. For example, the following is a plausible pattern for a UNIX filename: "[-./[:alnum:]_~]\+" That is, diff --git a/src/regexp.c b/src/regexp.c --- a/src/regexp.c +++ b/src/regexp.c @@ -484,6 +484,12 @@ get_char_class(char_u **pp) #define CLASS_BACKSPACE 14 "escape:]", #define CLASS_ESCAPE 15 + "ident:]", +#define CLASS_IDENT 16 + "keyword:]", +#define CLASS_KEYWORD 17 + "fname:]", +#define CLASS_FNAME 18 }; #define CLASS_NONE 99 int i; @@ -698,6 +704,7 @@ static char_u *re_put_long(char_u *pr, l static int read_limits(long *, long *); static void regtail(char_u *, char_u *); static void regoptail(char_u *, char_u *); +static int reg_iswordc(int); static regengine_T bt_regengine; static regengine_T nfa_regengine; @@ -2545,6 +2552,21 @@ collection: case CLASS_ESCAPE: regc('\033'); break; + case CLASS_IDENT: + for (cu = 1; cu <= 255; cu++) + if (vim_isIDc(cu)) + regmbc(cu); + break; + case CLASS_KEYWORD: + for (cu = 1; cu <= 255; cu++) + if (reg_iswordc(cu)) + regmbc(cu); + break; + case CLASS_FNAME: + for (cu = 1; cu <= 255; cu++) + if (vim_isfilec(cu)) + regmbc(cu); + break; } } else @@ -3590,6 +3612,16 @@ free_regexp_stuff(void) #endif /* + * Return TRUE if character 'c' is included in 'iskeyword' option for + * "reg_buf" buffer. + */ + static int +reg_iswordc(int c) +{ + return vim_iswordc_buf(c, rex.reg_buf); +} + +/* * Get pointer to the line "lnum", which is relative to "reg_firstlnum". */ static char_u * diff --git a/src/regexp_nfa.c b/src/regexp_nfa.c --- a/src/regexp_nfa.c +++ b/src/regexp_nfa.c @@ -226,7 +226,10 @@ enum NFA_CLASS_TAB, NFA_CLASS_RETURN, NFA_CLASS_BACKSPACE, - NFA_CLASS_ESCAPE + NFA_CLASS_ESCAPE, + NFA_CLASS_IDENT, + NFA_CLASS_KEYWORD, + NFA_CLASS_FNAME }; /* Keep in sync with classchars. */ @@ -1718,6 +1721,15 @@ collection: case CLASS_ESCAPE: EMIT(NFA_CLASS_ESCAPE); break; + case CLASS_IDENT: + EMIT(NFA_CLASS_IDENT); + break; + case CLASS_KEYWORD: + EMIT(NFA_CLASS_KEYWORD); + break; + case CLASS_FNAME: + EMIT(NFA_CLASS_FNAME); + break; } EMIT(NFA_CONCAT); continue; @@ -2555,6 +2567,9 @@ nfa_set_code(int c) case NFA_CLASS_RETURN: STRCPY(code, "NFA_CLASS_RETURN"); break; case NFA_CLASS_BACKSPACE: STRCPY(code, "NFA_CLASS_BACKSPACE"); break; case NFA_CLASS_ESCAPE: STRCPY(code, "NFA_CLASS_ESCAPE"); break; + case NFA_CLASS_IDENT: STRCPY(code, "NFA_CLASS_IDENT"); break; + case NFA_CLASS_KEYWORD: STRCPY(code, "NFA_CLASS_KEYWORD"); break; + case NFA_CLASS_FNAME: STRCPY(code, "NFA_CLASS_FNAME"); break; case NFA_ANY: STRCPY(code, "NFA_ANY"); break; case NFA_IDENT: STRCPY(code, "NFA_IDENT"); break; @@ -4846,6 +4861,18 @@ check_char_class(int class, int c) if (c == '\033') return OK; break; + case NFA_CLASS_IDENT: + if (vim_isIDc(c)) + return OK; + break; + case NFA_CLASS_KEYWORD: + if (reg_iswordc(c)) + return OK; + break; + case NFA_CLASS_FNAME: + if (vim_isfilec(c)) + return OK; + break; default: /* should not be here :P */ diff --git a/src/testdir/test_regexp_utf8.vim b/src/testdir/test_regexp_utf8.vim --- a/src/testdir/test_regexp_utf8.vim +++ b/src/testdir/test_regexp_utf8.vim @@ -51,6 +51,12 @@ func s:classes_test() let tabchar = '' let upperchars = '' let xdigitchars = '' + let identchars = '' + let identchars1 = '' + let kwordchars = '' + let kwordchars1 = '' + let fnamechars = '' + let fnamechars1 = '' let i = 1 while i <= 255 let c = nr2char(i) @@ -102,6 +108,24 @@ func s:classes_test() if c =~ '[[:xdigit:]]' let xdigitchars .= c endif + if c =~ '[[:ident:]]' + let identchars .= c + endif + if c =~ '\i' + let identchars1 .= c + endif + if c =~ '[[:keyword:]]' + let kwordchars .= c + endif + if c =~ '\k' + let kwordchars1 .= c + endif + if c =~ '[[:fname:]]' + let fnamechars .= c + endif + if c =~ '\f' + let fnamechars1 .= c + endif let i += 1 endwhile @@ -121,6 +145,37 @@ func s:classes_test() call assert_equal("\t\n\x0b\f\r ", spacechars) call assert_equal("\t", tabchar) call assert_equal('0123456789ABCDEFabcdef', xdigitchars) + + if has('win32') + let identchars_ok = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§µÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ' + let kwordchars_ok = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyzµÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ' + elseif has('ebcdic') + let identchars_ok = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz€ŒŽœž¬®µº¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ' + let kwordchars_ok = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz€ŒŽœž¬®µº¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ' + else + let identchars_ok = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyzµÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ' + let kwordchars_ok = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyzµÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ' + endif + + if has('win32') + let fnamechars_ok = '!#$%+,-./0123456789:=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]_abcdefghijklmnopqrstuvwxyz{}~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ' + elseif has('amiga') + let fnamechars_ok = '$+,-./0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ' + elseif has('vms') + let fnamechars_ok = '#$%+,-./0123456789:;<>ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_abcdefghijklmnopqrstuvwxyz~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ' + elseif has('ebcdic') + let fnamechars_ok = '#$%+,-./=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ' + else + let fnamechars_ok = '#$%+,-./0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ' + endif + + call assert_equal(identchars_ok, identchars) + call assert_equal(kwordchars_ok, kwordchars) + call assert_equal(fnamechars_ok, fnamechars) + + call assert_equal(identchars1, identchars) + call assert_equal(kwordchars1, kwordchars) + call assert_equal(fnamechars1, fnamechars) endfunc func Test_classes_re1() diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -784,6 +784,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 862, +/**/ 861, /**/ 860,