diff options
author | Bram Moolenaar <Bram@vim.org> | 2014-01-14 16:55:00 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2014-01-14 16:55:00 +0100 |
commit | 1028f4d75ee04261f1338620c22f388a05098bb0 (patch) | |
tree | 46c911fb9aaca60b7caad845dcb8dce1915eaf06 | |
parent | 063a46ba77c3251f0b5245e872dcbad003c71024 (diff) | |
download | vim-git-1028f4d75ee04261f1338620c22f388a05098bb0.tar.gz |
updated for version 7.4.152v7.4.152
Problem: Python: Cannot iterate over options.
Solution: Add options iterator. (ZyX)
-rw-r--r-- | src/if_py_both.h | 86 | ||||
-rw-r--r-- | src/option.c | 67 | ||||
-rw-r--r-- | src/proto/option.pro | 1 | ||||
-rw-r--r-- | src/testdir/test86.in | 14 | ||||
-rw-r--r-- | src/testdir/test86.ok | 41 | ||||
-rw-r--r-- | src/testdir/test87.in | 14 | ||||
-rw-r--r-- | src/testdir/test87.ok | 41 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim.h | 1 |
9 files changed, 261 insertions, 6 deletions
diff --git a/src/if_py_both.h b/src/if_py_both.h index 6e3939abe..01cbe418c 100644 --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -2949,10 +2949,10 @@ typedef int (*checkfun)(void *); typedef struct { PyObject_HEAD - int opt_type; - void *from; - checkfun Check; - PyObject *fromObj; + int opt_type; + void *from; + checkfun Check; + PyObject *fromObj; } OptionsObject; static int @@ -3072,6 +3072,69 @@ OptionsItem(OptionsObject *self, PyObject *keyObject) } static int +OptionsContains(OptionsObject *self, PyObject *keyObject) +{ + char_u *key; + PyObject *todecref; + + if (!(key = StringToChars(keyObject, &todecref))) + return -1; + + if (*key == NUL) + { + Py_XDECREF(todecref); + return 0; + } + + if (get_option_value_strict(key, NULL, NULL, self->opt_type, NULL)) + { + Py_XDECREF(todecref); + return 1; + } + else + { + Py_XDECREF(todecref); + return 0; + } +} + +typedef struct +{ + void *lastoption; + int opt_type; +} optiterinfo_T; + + static PyObject * +OptionsIterNext(optiterinfo_T **oii) +{ + char_u *name; + + if ((name = option_iter_next(&((*oii)->lastoption), (*oii)->opt_type))) + return PyString_FromString((char *)name); + + return NULL; +} + + static PyObject * +OptionsIter(OptionsObject *self) +{ + optiterinfo_T *oii; + + if (!(oii = PyMem_New(optiterinfo_T, 1))) + { + PyErr_NoMemory(); + return NULL; + } + + oii->opt_type = self->opt_type; + oii->lastoption = NULL; + + return IterNew(oii, + (destructorfun) PyMem_Free, (nextfun) OptionsIterNext, + NULL, NULL); +} + + static int set_option_value_err(char_u *key, int numval, char_u *stringval, int opt_flags) { char_u *errmsg; @@ -3231,6 +3294,19 @@ OptionsAssItem(OptionsObject *self, PyObject *keyObject, PyObject *valObject) return ret; } +static PySequenceMethods OptionsAsSeq = { + 0, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + 0, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + (objobjproc) OptionsContains, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + static PyMappingMethods OptionsAsMapping = { (lenfunc) NULL, (binaryfunc) OptionsItem, @@ -6121,8 +6197,10 @@ init_structs(void) vim_memset(&OptionsType, 0, sizeof(OptionsType)); OptionsType.tp_name = "vim.options"; OptionsType.tp_basicsize = sizeof(OptionsObject); + OptionsType.tp_as_sequence = &OptionsAsSeq; OptionsType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC; OptionsType.tp_doc = "object for manipulating options"; + OptionsType.tp_iter = (getiterfunc)OptionsIter; OptionsType.tp_as_mapping = &OptionsAsMapping; OptionsType.tp_dealloc = (destructor)OptionsDestructor; OptionsType.tp_traverse = (traverseproc)OptionsTraverse; diff --git a/src/option.c b/src/option.c index 4e087a58b..8c72da639 100644 --- a/src/option.c +++ b/src/option.c @@ -8861,7 +8861,7 @@ get_option_value(name, numval, stringval, opt_flags) } #endif -#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) +#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO) /* * Returns the option attributes and its value. Unlike the above function it * will return either global value or local value of the option depending on @@ -8874,7 +8874,8 @@ get_option_value(name, numval, stringval, opt_flags) * opt_type). Uses * * Returned flags: - * 0 hidden or unknown option + * 0 hidden or unknown option, also option that does not have requested + * type (see SREQ_* in vim.h) * see SOPT_* in vim.h for other flags * * Possible opt_type values: see SREQ_* in vim.h @@ -8997,6 +8998,68 @@ get_option_value_strict(name, numval, stringval, opt_type, from) return r; } + +/* + * Iterate over options. First argument is a pointer to a pointer to a structure + * inside options[] array, second is option type like in the above function. + * + * If first argument points to NULL it is assumed that iteration just started + * and caller needs the very first value. + * If first argument points to the end marker function returns NULL and sets + * first argument to NULL. + * + * Returns full option name for current option on each call. + */ + char_u * +option_iter_next(option, opt_type) + void **option; + int opt_type; +{ + struct vimoption *ret = NULL; + do + { + if (*option == NULL) + *option = (void *) options; + else if (((struct vimoption *) (*option))->fullname == NULL) + { + *option = NULL; + return NULL; + } + else + *option = (void *) (((struct vimoption *) (*option)) + 1); + + ret = ((struct vimoption *) (*option)); + + /* Hidden option */ + if (ret->var == NULL) + { + ret = NULL; + continue; + } + + switch (opt_type) + { + case SREQ_GLOBAL: + if (!(ret->indir == PV_NONE || ret->indir & PV_BOTH)) + ret = NULL; + break; + case SREQ_BUF: + if (!(ret->indir & PV_BUF)) + ret = NULL; + break; + case SREQ_WIN: + if (!(ret->indir & PV_WIN)) + ret = NULL; + break; + default: + EMSG2(_(e_intern2), "option_iter_next()"); + return NULL; + } + } + while (ret == NULL); + + return (char_u *)ret->fullname; +} #endif /* diff --git a/src/proto/option.pro b/src/proto/option.pro index cd3afbf79..4347d6591 100644 --- a/src/proto/option.pro +++ b/src/proto/option.pro @@ -23,6 +23,7 @@ char_u *check_colorcolumn __ARGS((win_T *wp)); char_u *check_stl_option __ARGS((char_u *s)); int get_option_value __ARGS((char_u *name, long *numval, char_u **stringval, int opt_flags)); int get_option_value_strict __ARGS((char_u *name, long *numval, char_u **stringval, int opt_type, void *from)); +char_u *option_iter_next __ARGS((void **option, int opt_type)); char_u *set_option_value __ARGS((char_u *name, long number, char_u *string, int opt_flags)); char_u *get_term_code __ARGS((char_u *tname)); char_u *get_highlight_default __ARGS((void)); diff --git a/src/testdir/test86.in b/src/testdir/test86.in index 1ccf7bd3d..240e07e47 100644 --- a/src/testdir/test86.in +++ b/src/testdir/test86.in @@ -506,6 +506,11 @@ EOF :py bopts1=vim.buffers[vim.bindeval("g:bufs")[2]].options :py bopts2=vim.buffers[vim.bindeval("g:bufs")[1]].options :py bopts3=vim.buffers[vim.bindeval("g:bufs")[0]].options +:$put ='wopts iters equal: '.pyeval('list(wopts1) == list(wopts2)') +:$put ='bopts iters equal: '.pyeval('list(bopts1) == list(bopts2)') +:py gset=set(iter(gopts1)) +:py wset=set(iter(wopts1)) +:py bset=set(iter(bopts1)) :set path=.,..,, :let lst=[] :let lst+=[['paste', 1, 0, 1, 2, 1, 1, 0 ]] @@ -536,6 +541,8 @@ EOF : py oval3=bool(oval3) : endif : put ='>>> '.oname +: $put =' g/w/b:'.pyeval('oname in gset').'/'.pyeval('oname in wset').'/'.pyeval('oname in bset') +: $put =' g/w/b (in):'.pyeval('oname in gopts1').'/'.pyeval('oname in wopts1').'/'.pyeval('oname in bopts1') : for v in ['gopts1', 'wopts1', 'bopts1'] : try : put =' p/'.v.': '.Ev('repr('.v.'['''.oname.'''])') @@ -1122,6 +1129,13 @@ ee('import failing_import') ee('import failing') vim.options['rtp'] = old_rtp del old_rtp +cb.append("> Options") +cb.append(">> OptionsItem") +ee('vim.options["abcQ"]') +ee('vim.options[""]') +stringtochars_test('vim.options[%s]') +cb.append(">> OptionsContains") +stringtochars_test('%s in vim.options') cb.append("> Dictionary") cb.append(">> DictionaryConstructor") ee('vim.Dictionary("abcI")') diff --git a/src/testdir/test86.ok b/src/testdir/test86.ok index 42cb0259c..257a5ee4c 100644 --- a/src/testdir/test86.ok +++ b/src/testdir/test86.ok @@ -112,7 +112,11 @@ bac def bar jkl +wopts iters equal: 1 +bopts iters equal: 1 >>> paste + g/w/b:1/0/0 + g/w/b (in):1/0/0 p/gopts1: False p/wopts1! KeyError inv: 2! KeyError @@ -133,6 +137,8 @@ jkl W: 1:1 2:1 3:1 4:1 B: 1:1 2:1 3:1 4:1 >>> previewheight + g/w/b:1/0/0 + g/w/b (in):1/0/0 p/gopts1: 12 inv: 'a'! TypeError p/wopts1! KeyError @@ -154,6 +160,8 @@ jkl W: 1:5 2:5 3:5 4:5 B: 1:5 2:5 3:5 4:5 >>> operatorfunc + g/w/b:1/0/0 + g/w/b (in):1/0/0 p/gopts1: '' inv: 2! TypeError p/wopts1! KeyError @@ -175,6 +183,8 @@ jkl W: 1:'A' 2:'A' 3:'A' 4:'A' B: 1:'A' 2:'A' 3:'A' 4:'A' >>> number + g/w/b:0/1/0 + g/w/b (in):0/1/0 p/gopts1! KeyError inv: 0! KeyError gopts1! KeyError @@ -193,6 +203,8 @@ jkl W: 1:1 2:1 3:0 4:0 B: 1:1 2:1 3:0 4:0 >>> numberwidth + g/w/b:0/1/0 + g/w/b (in):0/1/0 p/gopts1! KeyError inv: -100! KeyError gopts1! KeyError @@ -212,6 +224,8 @@ jkl W: 1:3 2:5 3:2 4:8 B: 1:3 2:5 3:2 4:8 >>> colorcolumn + g/w/b:0/1/0 + g/w/b (in):0/1/0 p/gopts1! KeyError inv: 'abc4'! KeyError gopts1! KeyError @@ -231,6 +245,8 @@ jkl W: 1:'+2' 2:'+3' 3:'+1' 4:'' B: 1:'+2' 2:'+3' 3:'+1' 4:'' >>> statusline + g/w/b:1/1/0 + g/w/b (in):1/1/0 p/gopts1: '' inv: 0! TypeError p/wopts1: None @@ -248,6 +264,8 @@ jkl W: 1:'2' 2:'1' 3:'1' 4:'1' B: 1:'2' 2:'1' 3:'1' 4:'1' >>> autoindent + g/w/b:0/0/1 + g/w/b (in):0/0/1 p/gopts1! KeyError inv: 2! KeyError gopts1! KeyError @@ -266,6 +284,8 @@ jkl W: 1:0 2:1 3:0 4:1 B: 1:0 2:1 3:0 4:1 >>> shiftwidth + g/w/b:0/0/1 + g/w/b (in):0/0/1 p/gopts1! KeyError inv: 3! KeyError gopts1! KeyError @@ -284,6 +304,8 @@ jkl W: 1:0 2:2 3:8 4:1 B: 1:0 2:2 3:8 4:1 >>> omnifunc + g/w/b:0/0/1 + g/w/b (in):0/0/1 p/gopts1! KeyError inv: 1! KeyError gopts1! KeyError @@ -303,6 +325,8 @@ jkl W: 1:'A' 2:'B' 3:'' 4:'C' B: 1:'A' 2:'B' 3:'' 4:'C' >>> preserveindent + g/w/b:0/0/1 + g/w/b (in):0/0/1 p/gopts1! KeyError inv: 2! KeyError gopts1! KeyError @@ -321,6 +345,8 @@ jkl W: 1:0 2:1 3:0 4:1 B: 1:0 2:1 3:0 4:1 >>> path + g/w/b:1/0/1 + g/w/b (in):1/0/1 p/gopts1: '.,..,,' inv: 0! TypeError p/wopts1! KeyError @@ -509,6 +535,21 @@ vim.foreach_rtp(int, 2):TypeError:('foreach_rtp() takes exactly one argument (2 import xxx_no_such_module_xxx:ImportError:('No module named xxx_no_such_module_xxx',) import failing_import:ImportError:('No module named failing_import',) import failing:NotImplementedError:() +> Options +>> OptionsItem +vim.options["abcQ"]:KeyError:('abcQ',) +vim.options[""]:ValueError:('empty keys are not allowed',) +>>> Testing StringToChars using vim.options[%s] +vim.options[1]:TypeError:('expected str() or unicode() instance, but got int',) +vim.options[u"\0"]:TypeError:('expected string without null bytes',) +vim.options["\0"]:TypeError:('expected string without null bytes',) +<<< Finished +>> OptionsContains +>>> Testing StringToChars using %s in vim.options +1 in vim.options:TypeError:('expected str() or unicode() instance, but got int',) +u"\0" in vim.options:TypeError:('expected string without null bytes',) +"\0" in vim.options:TypeError:('expected string without null bytes',) +<<< Finished > Dictionary >> DictionaryConstructor vim.Dictionary("abcI"):ValueError:('expected sequence element of size 2, but got sequence of size 1',) diff --git a/src/testdir/test87.in b/src/testdir/test87.in index 79b24b00d..e45883b59 100644 --- a/src/testdir/test87.in +++ b/src/testdir/test87.in @@ -503,6 +503,11 @@ EOF :py3 bopts1=vim.buffers[vim.bindeval("g:bufs")[2]].options :py3 bopts2=vim.buffers[vim.bindeval("g:bufs")[1]].options :py3 bopts3=vim.buffers[vim.bindeval("g:bufs")[0]].options +:$put ='wopts iters equal: '.py3eval('list(wopts1) == list(wopts2)') +:$put ='bopts iters equal: '.py3eval('list(bopts1) == list(bopts2)') +:py3 gset=set(iter(gopts1)) +:py3 wset=set(iter(wopts1)) +:py3 bset=set(iter(bopts1)) :set path=.,..,, :let lst=[] :let lst+=[['paste', 1, 0, 1, 2, 1, 1, 0 ]] @@ -533,6 +538,8 @@ EOF : py3 oval3=bool(oval3) : endif : put ='>>> '.oname +: $put =' g/w/b:'.py3eval('oname in gset').'/'.py3eval('oname in wset').'/'.py3eval('oname in bset') +: $put =' g/w/b (in):'.py3eval('oname in gopts1').'/'.py3eval('oname in wopts1').'/'.py3eval('oname in bopts1') : for v in ['gopts1', 'wopts1', 'bopts1'] : try : put =' p/'.v.': '.Ev('repr('.v.'['''.oname.'''])') @@ -1099,6 +1106,13 @@ ee('import failing_import') ee('import failing') vim.options['rtp'] = old_rtp del old_rtp +cb.append("> Options") +cb.append(">> OptionsItem") +ee('vim.options["abcQ"]') +ee('vim.options[""]') +stringtochars_test('vim.options[%s]') +cb.append(">> OptionsContains") +stringtochars_test('%s in vim.options') cb.append("> Dictionary") cb.append(">> DictionaryConstructor") ee('vim.Dictionary("abcI")') diff --git a/src/testdir/test87.ok b/src/testdir/test87.ok index 57ac1a63a..d1ec84c6b 100644 --- a/src/testdir/test87.ok +++ b/src/testdir/test87.ok @@ -112,7 +112,11 @@ bac def bar jkl +wopts iters equal: 1 +bopts iters equal: 1 >>> paste + g/w/b:1/0/0 + g/w/b (in):1/0/0 p/gopts1: False p/wopts1! KeyError inv: 2! KeyError @@ -133,6 +137,8 @@ jkl W: 1:1 2:1 3:1 4:1 B: 1:1 2:1 3:1 4:1 >>> previewheight + g/w/b:1/0/0 + g/w/b (in):1/0/0 p/gopts1: 12 inv: 'a'! TypeError p/wopts1! KeyError @@ -154,6 +160,8 @@ jkl W: 1:5 2:5 3:5 4:5 B: 1:5 2:5 3:5 4:5 >>> operatorfunc + g/w/b:1/0/0 + g/w/b (in):1/0/0 p/gopts1: b'' inv: 2! TypeError p/wopts1! KeyError @@ -175,6 +183,8 @@ jkl W: 1:'A' 2:'A' 3:'A' 4:'A' B: 1:'A' 2:'A' 3:'A' 4:'A' >>> number + g/w/b:0/1/0 + g/w/b (in):0/1/0 p/gopts1! KeyError inv: 0! KeyError gopts1! KeyError @@ -193,6 +203,8 @@ jkl W: 1:1 2:1 3:0 4:0 B: 1:1 2:1 3:0 4:0 >>> numberwidth + g/w/b:0/1/0 + g/w/b (in):0/1/0 p/gopts1! KeyError inv: -100! KeyError gopts1! KeyError @@ -212,6 +224,8 @@ jkl W: 1:3 2:5 3:2 4:8 B: 1:3 2:5 3:2 4:8 >>> colorcolumn + g/w/b:0/1/0 + g/w/b (in):0/1/0 p/gopts1! KeyError inv: 'abc4'! KeyError gopts1! KeyError @@ -231,6 +245,8 @@ jkl W: 1:'+2' 2:'+3' 3:'+1' 4:'' B: 1:'+2' 2:'+3' 3:'+1' 4:'' >>> statusline + g/w/b:1/1/0 + g/w/b (in):1/1/0 p/gopts1: b'' inv: 0! TypeError p/wopts1: None @@ -248,6 +264,8 @@ jkl W: 1:'2' 2:'1' 3:'1' 4:'1' B: 1:'2' 2:'1' 3:'1' 4:'1' >>> autoindent + g/w/b:0/0/1 + g/w/b (in):0/0/1 p/gopts1! KeyError inv: 2! KeyError gopts1! KeyError @@ -266,6 +284,8 @@ jkl W: 1:0 2:1 3:0 4:1 B: 1:0 2:1 3:0 4:1 >>> shiftwidth + g/w/b:0/0/1 + g/w/b (in):0/0/1 p/gopts1! KeyError inv: 3! KeyError gopts1! KeyError @@ -284,6 +304,8 @@ jkl W: 1:0 2:2 3:8 4:1 B: 1:0 2:2 3:8 4:1 >>> omnifunc + g/w/b:0/0/1 + g/w/b (in):0/0/1 p/gopts1! KeyError inv: 1! KeyError gopts1! KeyError @@ -303,6 +325,8 @@ jkl W: 1:'A' 2:'B' 3:'' 4:'C' B: 1:'A' 2:'B' 3:'' 4:'C' >>> preserveindent + g/w/b:0/0/1 + g/w/b (in):0/0/1 p/gopts1! KeyError inv: 2! KeyError gopts1! KeyError @@ -321,6 +345,8 @@ jkl W: 1:0 2:1 3:0 4:1 B: 1:0 2:1 3:0 4:1 >>> path + g/w/b:1/0/1 + g/w/b (in):1/0/1 p/gopts1: b'.,..,,' inv: 0! TypeError p/wopts1! KeyError @@ -509,6 +535,21 @@ vim.foreach_rtp(int, 2):(<class 'TypeError'>, TypeError('foreach_rtp() takes exa import xxx_no_such_module_xxx:(<class 'ImportError'>, ImportError('No module named xxx_no_such_module_xxx',)) import failing_import:(<class 'ImportError'>, ImportError('No module named failing_import',)) import failing:(<class 'NotImplementedError'>, NotImplementedError()) +> Options +>> OptionsItem +vim.options["abcQ"]:(<class 'KeyError'>, KeyError('abcQ',)) +vim.options[""]:(<class 'ValueError'>, ValueError('empty keys are not allowed',)) +>>> Testing StringToChars using vim.options[%s] +vim.options[1]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',)) +vim.options[b"\0"]:(<class 'TypeError'>, TypeError('expected bytes with no null',)) +vim.options["\0"]:(<class 'TypeError'>, TypeError('expected bytes with no null',)) +<<< Finished +>> OptionsContains +>>> Testing StringToChars using %s in vim.options +1 in vim.options:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',)) +b"\0" in vim.options:(<class 'TypeError'>, TypeError('expected bytes with no null',)) +"\0" in vim.options:(<class 'TypeError'>, TypeError('expected bytes with no null',)) +<<< Finished > Dictionary >> DictionaryConstructor vim.Dictionary("abcI"):(<class 'ValueError'>, ValueError('expected sequence element of size 2, but got sequence of size 1',)) diff --git a/src/version.c b/src/version.c index c0fe21f3f..8a472146d 100644 --- a/src/version.c +++ b/src/version.c @@ -739,6 +739,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 152, +/**/ 151, /**/ 150, @@ -2249,6 +2249,7 @@ typedef int VimClipboard; /* This is required for the prototypes. */ #define SOPT_BUF 0x20 /* Option has buffer-local value */ #define SOPT_UNSET 0x40 /* Option does not have local value set */ +/* Option types for various functions in option.c */ #define SREQ_GLOBAL 0 /* Request global option */ #define SREQ_WIN 1 /* Request window-local option */ #define SREQ_BUF 2 /* Request buffer-local option */ |