To: vim_dev@googlegroups.com Subject: Patch 7.4.152 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.152 Problem: Python: Cannot iterate over options. Solution: Add options iterator. (ZyX) Files: src/if_py_both.h, src/option.c, src/proto/option.pro, src/testdir/test86.in, src/testdir/test86.ok, src/testdir/test87.in, src/testdir/test87.ok, src/vim.h *** ../vim-7.4.151/src/if_py_both.h 2014-01-14 16:36:40.000000000 +0100 --- src/if_py_both.h 2014-01-14 16:51:30.000000000 +0100 *************** *** 2949,2958 **** typedef struct { PyObject_HEAD ! int opt_type; ! void *from; ! checkfun Check; ! PyObject *fromObj; } OptionsObject; static int --- 2949,2958 ---- typedef struct { PyObject_HEAD ! int opt_type; ! void *from; ! checkfun Check; ! PyObject *fromObj; } OptionsObject; static int *************** *** 3072,3077 **** --- 3072,3140 ---- } 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,3236 **** --- 3294,3312 ---- 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,6128 **** --- 6197,6206 ---- 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; *** ../vim-7.4.151/src/option.c 2013-11-12 04:43:57.000000000 +0100 --- src/option.c 2014-01-14 16:50:52.000000000 +0100 *************** *** 8861,8867 **** } #endif ! #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) /* * 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 --- 8861,8867 ---- } #endif ! #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,8880 **** * opt_type). Uses * * Returned flags: ! * 0 hidden or unknown option * see SOPT_* in vim.h for other flags * * Possible opt_type values: see SREQ_* in vim.h --- 8874,8881 ---- * opt_type). Uses * * Returned flags: ! * 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,9002 **** --- 8998,9065 ---- 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 /* *** ../vim-7.4.151/src/proto/option.pro 2013-11-05 07:12:59.000000000 +0100 --- src/proto/option.pro 2014-01-14 16:51:41.000000000 +0100 *************** *** 23,28 **** --- 23,29 ---- 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)); *** ../vim-7.4.151/src/testdir/test86.in 2014-01-14 16:36:40.000000000 +0100 --- src/testdir/test86.in 2014-01-14 16:49:10.000000000 +0100 *************** *** 506,511 **** --- 506,516 ---- :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,541 **** --- 541,548 ---- : 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,1127 **** --- 1129,1141 ---- 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")') *** ../vim-7.4.151/src/testdir/test86.ok 2014-01-14 16:36:40.000000000 +0100 --- src/testdir/test86.ok 2014-01-14 16:49:10.000000000 +0100 *************** *** 112,118 **** --- 112,122 ---- 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,138 **** --- 137,144 ---- 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,159 **** --- 160,167 ---- 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,180 **** --- 183,190 ---- 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,198 **** --- 203,210 ---- 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,217 **** --- 224,231 ---- 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,236 **** --- 245,252 ---- 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,253 **** --- 264,271 ---- 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,271 **** --- 284,291 ---- 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,289 **** --- 304,311 ---- 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,308 **** --- 325,332 ---- 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,326 **** --- 345,352 ---- 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,514 **** --- 535,555 ---- 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',) *** ../vim-7.4.151/src/testdir/test87.in 2014-01-14 16:36:40.000000000 +0100 --- src/testdir/test87.in 2014-01-14 16:49:10.000000000 +0100 *************** *** 503,508 **** --- 503,513 ---- :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,538 **** --- 538,545 ---- : 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,1104 **** --- 1106,1118 ---- 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")') *** ../vim-7.4.151/src/testdir/test87.ok 2014-01-14 16:36:40.000000000 +0100 --- src/testdir/test87.ok 2014-01-14 16:49:10.000000000 +0100 *************** *** 112,118 **** --- 112,122 ---- 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,138 **** --- 137,144 ---- 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,159 **** --- 160,167 ---- 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,180 **** --- 183,190 ---- 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,198 **** --- 203,210 ---- 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,217 **** --- 224,231 ---- 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,236 **** --- 245,252 ---- 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,253 **** --- 264,271 ---- 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,271 **** --- 284,291 ---- 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,289 **** --- 304,311 ---- 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,308 **** --- 325,332 ---- 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,326 **** --- 345,352 ---- 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,514 **** --- 535,555 ---- 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 bytes() or str() instance, but got int',)) + vim.options[b"\0"]:(, TypeError('expected bytes with no null',)) + vim.options["\0"]:(, TypeError('expected bytes with no null',)) + <<< Finished + >> OptionsContains + >>> Testing StringToChars using %s in vim.options + 1 in vim.options:(, TypeError('expected bytes() or str() instance, but got int',)) + b"\0" in vim.options:(, TypeError('expected bytes with no null',)) + "\0" in vim.options:(, TypeError('expected bytes with no null',)) + <<< Finished > Dictionary >> DictionaryConstructor vim.Dictionary("abcI"):(, ValueError('expected sequence element of size 2, but got sequence of size 1',)) *** ../vim-7.4.151/src/vim.h 2013-11-09 03:31:45.000000000 +0100 --- src/vim.h 2014-01-14 16:49:10.000000000 +0100 *************** *** 2249,2254 **** --- 2249,2255 ---- #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 */ *** ../vim-7.4.151/src/version.c 2014-01-14 16:36:40.000000000 +0100 --- src/version.c 2014-01-14 16:43:58.000000000 +0100 *************** *** 740,741 **** --- 740,743 ---- { /* Add new patch number below this line */ + /**/ + 152, /**/ -- hundred-and-one symptoms of being an internet addict: 160. You get in the elevator and double-click the button for the floor you want. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///