| To: vim_dev@googlegroups.com |
| Subject: Patch 7.3.1061 |
| Fcc: outbox |
| From: Bram Moolenaar <Bram@moolenaar.net> |
| Mime-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| |
| Patch 7.3.1061 |
| Problem: Python: Dictionary is not standard. |
| Solution: Python patch 20: Add standard methods and fields. (ZyX) |
| Files: runtime/doc/if_pyth.txt, src/eval.c, src/if_py_both.h, |
| src/if_python3.c, src/if_python.c, src/proto/eval.pro, |
| src/testdir/test86.in, src/testdir/test86.ok, |
| src/testdir/test87.in, src/testdir/test87.ok |
| |
| |
| |
| |
| |
| *** 12,20 **** |
| 4. Range objects |python-range| |
| 5. Window objects |python-window| |
| 6. Tab page objects |python-tabpage| |
| ! 7. pyeval(), py3eval() Vim functions |python-pyeval| |
| ! 8. Dynamic loading |python-dynamic| |
| ! 9. Python 3 |python3| |
| |
| {Vi does not have any of these commands} |
| |
| --- 12,21 ---- |
| 4. Range objects |python-range| |
| 5. Window objects |python-window| |
| 6. Tab page objects |python-tabpage| |
| ! 7. vim.bindeval objects |python-bindeval-objects| |
| ! 8. pyeval(), py3eval() Vim functions |python-pyeval| |
| ! 9. Dynamic loading |python-dynamic| |
| ! 10. Python 3 |python3| |
| |
| {Vi does not have any of these commands} |
| |
| |
| *** 171,217 **** |
| 'eval_expr', 'kind': 'f', 'filename': './src/eval.c'}] |
| |
| vim.bindeval(str) *python-bindeval* |
| ! Like |python-eval|, but |
| ! 1. if expression evaluates to |List| or |Dictionary| it is returned as |
| ! vimlist or vimdictionary python type that are connected to original |
| ! list or dictionary. Thus modifications to these objects imply |
| ! modifications of the original. |
| ! |
| ! Additionally, vim.List and vim.Dictionary type have read-write |
| ! `.locked` attribute that returns |
| ! Value Meaning ~ |
| ! zero Variable is not locked |
| ! vim.VAR_LOCKED Variable is locked, but can be unlocked |
| ! vim.VAR_FIXED Variable is locked and can't be unlocked |
| ! integer constants. If variable is not fixed, you can do |
| ! `var.locked=True` to lock it and `var.locked=False` to unlock. |
| ! There is no recursive locking like |:lockvar|! does. There is also |
| ! no way to lock a specific key or check whether it is locked (in any |
| ! case these locks are ignored by anything except |:let|: |extend()| |
| ! does not care, neither does python interface). |
| ! |
| ! vim.Dictionary type also supports `.scope` attribute which is one |
| ! of |
| ! Value Meaning ~ |
| ! zero Dictionary is not a scope one |
| ! vim.VAR_DEF_SCOPE Function-local or global scope dictionary |
| ! vim.VAR_SCOPE Other scope dictionary |
| ! |
| ! 2. if expression evaluates to a function reference, then it returns |
| ! callable vim.Function object. Use self keyword argument to assign |
| ! |self| object for dictionary functions. |
| ! |
| ! Note: this function has the same behavior as |lua-eval| (except that |
| ! lua does not support running vim functions), |python-eval| is |
| ! kept for backwards compatibility in order not to make scripts |
| ! relying on outputs of vim.eval() being a copy of original or |
| ! vim.eval("1") returning a string. |
| ! |
| ! You can use "List", "Dictionary" and "Function" vim module attributes |
| ! to test whether object has given type. These types are currently not |
| ! subclassable, neither they contain constructors, so you can use them |
| ! only for checks like `isinstance(obj, vim.List)`. |
| ! |
| |
| Error object of the "vim" module |
| |
| --- 172,180 ---- |
| 'eval_expr', 'kind': 'f', 'filename': './src/eval.c'}] |
| |
| vim.bindeval(str) *python-bindeval* |
| ! Like |python-eval|, but returns special objects described in |
| ! |python-bindeval-objects|. These python objects let you modify (|List| |
| ! or |Dictionary|) or call (|Funcref|) vim objecs. |
| |
| Error object of the "vim" module |
| |
| |
| *** 497,509 **** |
| TabPage object type is available using "TabPage" attribute of vim module. |
| |
| |
| ! 7. pyeval() and py3eval() Vim functions *python-pyeval* |
| |
| To facilitate bi-directional interface, you can use |pyeval()| and |py3eval()| |
| functions to evaluate Python expressions and pass their values to VimL. |
| |
| |
| ! 8. Dynamic loading *python-dynamic* |
| |
| On MS-Windows the Python library can be loaded dynamically. The |:version| |
| output then includes |+python/dyn|. |
| --- 460,549 ---- |
| TabPage object type is available using "TabPage" attribute of vim module. |
| |
| |
| ! 7. vim.bindeval objects *python-bindeval-objects* |
| ! |
| ! vim.Dictionary object *python-Dictionary* |
| ! Dictionary-like object providing access to vim |Dictionary| type. |
| ! Attributes: |
| ! Attribute Description ~ |
| ! locked One of *python-.locked* |
| ! Value Description ~ |
| ! zero Variable is not locked |
| ! vim.VAR_LOCKED Variable is locked, but can be unlocked |
| ! vim.VAR_FIXED Variable is locked and can't be unlocked |
| ! Read-write. You can unlock locked variable by assigning |
| ! `True` or `False` to this attribute. No recursive locking |
| ! is supported. |
| ! scope One of |
| ! Value Description ~ |
| ! zero Dictionary is not a scope one |
| ! vim.VAR_DEF_SCOPE |g:| or |l:| dictionary |
| ! vim.VAR_SCOPE Other scope dictionary, |
| ! see |internal-variables| |
| ! Methods: |
| ! Method Description ~ |
| ! keys() Returns a list with dictionary keys. |
| ! values() Returns a list with dictionary values. |
| ! items() Returns a list of 2-tuples with dictionary contents. |
| ! update(iterable) |
| ! update(dictionary) |
| ! update(**kwargs) |
| ! Adds keys to dictionary. |
| ! Examples: > |
| ! py d = vim.bindeval('{}') |
| ! d['a'] = 'b' # Item assignment |
| ! print d['a'] # getting item |
| ! d.update({'c': 'd'}) # .update(dictionary) |
| ! d.update(e='f') # .update(**kwargs) |
| ! d.update((('g', 'h'), ('i', 'j'))) # .update(iterable) |
| ! for key in d.keys(): # .keys() |
| ! for val in d.values(): # .values() |
| ! for key, val in d.items(): # .items() |
| ! print isinstance(d, vim.Dictionary) # True |
| ! for key in d: # Iteration over keys |
| ! < |
| ! Note: when iterating over keys you should not modify dictionary. |
| ! |
| ! vim.List object *python-List* |
| ! Sequence-like object providing access to vim |List| type. |
| ! Supports `.locked` attribute, see |python-.locked|. Also supports the |
| ! following methods: |
| ! Method Description ~ |
| ! extend(item) Add items to the list. |
| ! Examples: > |
| ! l = vim.bindeval('[]') |
| ! l.extend(['abc', 'def']) # .extend() method |
| ! print l[1:] # slicing |
| ! l[:0] = ['ghi', 'jkl'] # slice assignment |
| ! print l[0] # getting item |
| ! l[0] = 'mno' # assignment |
| ! for i in l: # iteration |
| ! print isinstance(l, vim.List) # True |
| ! |
| ! vim.Function object *python-Function* |
| ! Function-like object, acting like vim |Funcref| object. Supports `.name` |
| ! attribute and is callable. Accepts special keyword argument `self`, see |
| ! |Dictionary-function|. |
| ! Examples: > |
| ! f = vim.bindeval('function("tr")') |
| ! print f('abc', 'a', 'b') # Calls tr('abc', 'a', 'b') |
| ! vim.command(''' |
| ! function DictFun() dict |
| ! return self |
| ! endfunction |
| ! ''') |
| ! f = vim.bindeval('function("DictFun")') |
| ! print f(self={}) # Like call('DictFun', [], {}) |
| ! print isinstance(f, vim.Function) # True |
| ! |
| ! ============================================================================== |
| ! 8. pyeval() and py3eval() Vim functions *python-pyeval* |
| |
| To facilitate bi-directional interface, you can use |pyeval()| and |py3eval()| |
| functions to evaluate Python expressions and pass their values to VimL. |
| |
| |
| ! 9. Dynamic loading *python-dynamic* |
| |
| On MS-Windows the Python library can be loaded dynamically. The |:version| |
| output then includes |+python/dyn|. |
| |
| *** 520,526 **** |
| sure edit "gvim.exe" and search for "python\d*.dll\c". |
| |
| |
| ! 9. Python 3 *python3* |
| |
| *:py3* *:python3* |
| The `:py3` and `:python3` commands work similar to `:python`. A simple check |
| --- 560,566 ---- |
| sure edit "gvim.exe" and search for "python\d*.dll\c". |
| |
| |
| ! 10. Python 3 *python3* |
| |
| *:py3* *:python3* |
| The `:py3` and `:python3` commands work similar to `:python`. A simple check |
| |
| |
| |
| *** 10157,10162 **** |
| --- 10157,10218 ---- |
| } |
| |
| /* |
| + * Go over all entries in "d2" and add them to "d1". |
| + * When "action" is "error" then a duplicate key is an error. |
| + * When "action" is "force" then a duplicate key is overwritten. |
| + * Otherwise duplicate keys are ignored ("action" is "keep"). |
| + */ |
| + void |
| + dict_extend(d1, d2, action) |
| + dict_T *d1; |
| + dict_T *d2; |
| + char_u *action; |
| + { |
| + dictitem_T *di1; |
| + hashitem_T *hi2; |
| + int todo; |
| + |
| + todo = (int)d2->dv_hashtab.ht_used; |
| + for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2) |
| + { |
| + if (!HASHITEM_EMPTY(hi2)) |
| + { |
| + --todo; |
| + di1 = dict_find(d1, hi2->hi_key, -1); |
| + if (d1->dv_scope != 0) |
| + { |
| + /* Disallow replacing a builtin function in l: and g:. |
| + * Check the key to be valid when adding to any |
| + * scope. */ |
| + if (d1->dv_scope == VAR_DEF_SCOPE |
| + && HI2DI(hi2)->di_tv.v_type == VAR_FUNC |
| + && var_check_func_name(hi2->hi_key, |
| + di1 == NULL)) |
| + break; |
| + if (!valid_varname(hi2->hi_key)) |
| + break; |
| + } |
| + if (di1 == NULL) |
| + { |
| + di1 = dictitem_copy(HI2DI(hi2)); |
| + if (di1 != NULL && dict_add(d1, di1) == FAIL) |
| + dictitem_free(di1); |
| + } |
| + else if (*action == 'e') |
| + { |
| + EMSG2(_("E737: Key already exists: %s"), hi2->hi_key); |
| + break; |
| + } |
| + else if (*action == 'f' && HI2DI(hi2) != di1) |
| + { |
| + clear_tv(&di1->di_tv); |
| + copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv); |
| + } |
| + } |
| + } |
| + } |
| + |
| + /* |
| * "extend(list, list [, idx])" function |
| * "extend(dict, dict [, action])" function |
| */ |
| |
| *** 10206,10217 **** |
| } |
| else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) |
| { |
| ! dict_T *d1, *d2; |
| ! dictitem_T *di1; |
| ! char_u *action; |
| ! int i; |
| ! hashitem_T *hi2; |
| ! int todo; |
| |
| d1 = argvars[0].vval.v_dict; |
| d2 = argvars[1].vval.v_dict; |
| --- 10262,10270 ---- |
| } |
| else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) |
| { |
| ! dict_T *d1, *d2; |
| ! char_u *action; |
| ! int i; |
| |
| d1 = argvars[0].vval.v_dict; |
| d2 = argvars[1].vval.v_dict; |
| |
| *** 10238,10283 **** |
| else |
| action = (char_u *)"force"; |
| |
| ! /* Go over all entries in the second dict and add them to the |
| ! * first dict. */ |
| ! todo = (int)d2->dv_hashtab.ht_used; |
| ! for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2) |
| ! { |
| ! if (!HASHITEM_EMPTY(hi2)) |
| ! { |
| ! --todo; |
| ! di1 = dict_find(d1, hi2->hi_key, -1); |
| ! if (d1->dv_scope != 0) |
| ! { |
| ! /* Disallow replacing a builtin function in l: and g:. |
| ! * Check the key to be valid when adding to any |
| ! * scope. */ |
| ! if (d1->dv_scope == VAR_DEF_SCOPE |
| ! && HI2DI(hi2)->di_tv.v_type == VAR_FUNC |
| ! && var_check_func_name(hi2->hi_key, |
| ! di1 == NULL)) |
| ! break; |
| ! if (!valid_varname(hi2->hi_key)) |
| ! break; |
| ! } |
| ! if (di1 == NULL) |
| ! { |
| ! di1 = dictitem_copy(HI2DI(hi2)); |
| ! if (di1 != NULL && dict_add(d1, di1) == FAIL) |
| ! dictitem_free(di1); |
| ! } |
| ! else if (*action == 'e') |
| ! { |
| ! EMSG2(_("E737: Key already exists: %s"), hi2->hi_key); |
| ! break; |
| ! } |
| ! else if (*action == 'f' && HI2DI(hi2) != di1) |
| ! { |
| ! clear_tv(&di1->di_tv); |
| ! copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv); |
| ! } |
| ! } |
| ! } |
| |
| copy_tv(&argvars[0], rettv); |
| } |
| --- 10291,10297 ---- |
| else |
| action = (char_u *)"force"; |
| |
| ! dict_extend(d1, d2, action); |
| |
| copy_tv(&argvars[0], rettv); |
| } |
| |
| |
| |
| *** 31,37 **** |
| #define INVALID_TABPAGE_VALUE ((tabpage_T *)(-1)) |
| |
| #define DICTKEY_DECL \ |
| ! PyObject *dictkey_todecref; |
| #define DICTKEY_CHECK_EMPTY(err) \ |
| if (*key == NUL) \ |
| { \ |
| --- 31,37 ---- |
| #define INVALID_TABPAGE_VALUE ((tabpage_T *)(-1)) |
| |
| #define DICTKEY_DECL \ |
| ! PyObject *dictkey_todecref = NULL; |
| #define DICTKEY_CHECK_EMPTY(err) \ |
| if (*key == NUL) \ |
| { \ |
| |
| *** 63,68 **** |
| --- 63,69 ---- |
| |
| static int ConvertFromPyObject(PyObject *, typval_T *); |
| static int _ConvertFromPyObject(PyObject *, typval_T *, PyObject *); |
| + static int ConvertFromPyMapping(PyObject *, typval_T *); |
| static PyObject *WindowNew(win_T *, tabpage_T *); |
| static PyObject *BufferNew (buf_T *); |
| static PyObject *LineToString(const char *); |
| |
| *** 877,888 **** |
| pylinkedlist_T ref; |
| } DictionaryObject; |
| |
| static PyObject * |
| ! DictionaryNew(dict_T *dict) |
| { |
| DictionaryObject *self; |
| |
| ! self = PyObject_NEW(DictionaryObject, &DictionaryType); |
| if (self == NULL) |
| return NULL; |
| self->dict = dict; |
| --- 878,893 ---- |
| pylinkedlist_T ref; |
| } DictionaryObject; |
| |
| + static PyObject *DictionaryUpdate(DictionaryObject *, PyObject *, PyObject *); |
| + |
| + #define NEW_DICTIONARY(dict) DictionaryNew(&DictionaryType, dict) |
| + |
| static PyObject * |
| ! DictionaryNew(PyTypeObject *subtype, dict_T *dict) |
| { |
| DictionaryObject *self; |
| |
| ! self = (DictionaryObject *) subtype->tp_alloc(subtype, 0); |
| if (self == NULL) |
| return NULL; |
| self->dict = dict; |
| |
| *** 893,898 **** |
| --- 898,946 ---- |
| return (PyObject *)(self); |
| } |
| |
| + static dict_T * |
| + py_dict_alloc() |
| + { |
| + dict_T *r; |
| + |
| + if (!(r = dict_alloc())) |
| + { |
| + PyErr_NoMemory(); |
| + return NULL; |
| + } |
| + ++r->dv_refcount; |
| + |
| + return r; |
| + } |
| + |
| + static PyObject * |
| + DictionaryConstructor(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) |
| + { |
| + DictionaryObject *self; |
| + dict_T *dict; |
| + |
| + if (!(dict = py_dict_alloc())) |
| + return NULL; |
| + |
| + self = (DictionaryObject *) DictionaryNew(subtype, dict); |
| + |
| + --dict->dv_refcount; |
| + |
| + if (kwargs || PyTuple_Size(args)) |
| + { |
| + PyObject *tmp; |
| + if (!(tmp = DictionaryUpdate(self, args, kwargs))) |
| + { |
| + Py_DECREF(self); |
| + return NULL; |
| + } |
| + |
| + Py_DECREF(tmp); |
| + } |
| + |
| + return (PyObject *)(self); |
| + } |
| + |
| static void |
| DictionaryDestructor(DictionaryObject *self) |
| { |
| |
| *** 918,924 **** |
| { |
| if (val == NULL) |
| { |
| ! PyErr_SetString(PyExc_AttributeError, _("Cannot delete DictionaryObject attributes")); |
| return -1; |
| } |
| |
| --- 966,973 ---- |
| { |
| if (val == NULL) |
| { |
| ! PyErr_SetString(PyExc_AttributeError, |
| ! _("cannot delete vim.Dictionary attributes")); |
| return -1; |
| } |
| |
| |
| *** 926,932 **** |
| { |
| if (self->dict->dv_lock == VAR_FIXED) |
| { |
| ! PyErr_SetString(PyExc_TypeError, _("Cannot modify fixed dictionary")); |
| return -1; |
| } |
| else |
| --- 975,981 ---- |
| { |
| if (self->dict->dv_lock == VAR_FIXED) |
| { |
| ! PyErr_SetString(PyExc_TypeError, _("cannot modify fixed dictionary")); |
| return -1; |
| } |
| else |
| |
| *** 943,949 **** |
| } |
| else |
| { |
| ! PyErr_SetString(PyExc_AttributeError, _("Cannot set this attribute")); |
| return -1; |
| } |
| } |
| --- 992,998 ---- |
| } |
| else |
| { |
| ! PyErr_SetString(PyExc_AttributeError, _("cannot set this attribute")); |
| return -1; |
| } |
| } |
| |
| *** 954,979 **** |
| return ((PyInt) (self->dict->dv_hashtab.ht_used)); |
| } |
| |
| static PyObject * |
| ! DictionaryItem(DictionaryObject *self, PyObject *keyObject) |
| { |
| char_u *key; |
| dictitem_T *di; |
| DICTKEY_DECL |
| |
| DICTKEY_GET(NULL, 0) |
| |
| ! di = dict_find(self->dict, key, -1); |
| |
| DICTKEY_UNREF |
| |
| ! if (di == NULL) |
| { |
| ! PyErr_SetObject(PyExc_KeyError, keyObject); |
| return NULL; |
| } |
| |
| ! return ConvertToPyObject(&di->di_tv); |
| } |
| |
| static PyInt |
| --- 1003,1172 ---- |
| return ((PyInt) (self->dict->dv_hashtab.ht_used)); |
| } |
| |
| + #define DICT_FLAG_HAS_DEFAULT 0x01 |
| + #define DICT_FLAG_POP 0x02 |
| + #define DICT_FLAG_NONE_DEFAULT 0x04 |
| + #define DICT_FLAG_RETURN_BOOL 0x08 /* Incompatible with DICT_FLAG_POP */ |
| + #define DICT_FLAG_RETURN_PAIR 0x10 |
| + |
| static PyObject * |
| ! _DictionaryItem(DictionaryObject *self, PyObject *args, int flags) |
| { |
| + PyObject *keyObject; |
| + PyObject *defObject = ((flags & DICT_FLAG_NONE_DEFAULT)? Py_None : NULL); |
| + PyObject *r; |
| char_u *key; |
| dictitem_T *di; |
| + dict_T *dict = self->dict; |
| + hashitem_T *hi; |
| + |
| DICTKEY_DECL |
| |
| + if (flags & DICT_FLAG_HAS_DEFAULT) |
| + { |
| + if (!PyArg_ParseTuple(args, "O|O", &keyObject, &defObject)) |
| + return NULL; |
| + } |
| + else |
| + keyObject = args; |
| + |
| + if (flags & DICT_FLAG_RETURN_BOOL) |
| + defObject = Py_False; |
| + |
| DICTKEY_GET(NULL, 0) |
| |
| ! hi = hash_find(&dict->dv_hashtab, key); |
| |
| DICTKEY_UNREF |
| |
| ! if (HASHITEM_EMPTY(hi)) |
| { |
| ! if (defObject) |
| ! { |
| ! Py_INCREF(defObject); |
| ! return defObject; |
| ! } |
| ! else |
| ! { |
| ! PyErr_SetObject(PyExc_KeyError, keyObject); |
| ! return NULL; |
| ! } |
| ! } |
| ! else if (flags & DICT_FLAG_RETURN_BOOL) |
| ! { |
| ! Py_INCREF(Py_True); |
| ! return Py_True; |
| ! } |
| ! |
| ! di = dict_lookup(hi); |
| ! |
| ! if (!(r = ConvertToPyObject(&di->di_tv))) |
| return NULL; |
| + |
| + if (flags & DICT_FLAG_POP) |
| + { |
| + if (dict->dv_lock) |
| + { |
| + PyErr_SetVim(_("dict is locked")); |
| + Py_DECREF(r); |
| + return NULL; |
| + } |
| + |
| + hash_remove(&dict->dv_hashtab, hi); |
| + dictitem_free(di); |
| } |
| |
| ! if (flags & DICT_FLAG_RETURN_PAIR) |
| ! { |
| ! PyObject *tmp = r; |
| ! |
| ! if (!(r = Py_BuildValue("(" Py_bytes_fmt "O)", hi->hi_key, tmp))) |
| ! { |
| ! Py_DECREF(tmp); |
| ! return NULL; |
| ! } |
| ! } |
| ! |
| ! return r; |
| ! } |
| ! |
| ! static PyObject * |
| ! DictionaryItem(DictionaryObject *self, PyObject *keyObject) |
| ! { |
| ! return _DictionaryItem(self, keyObject, 0); |
| ! } |
| ! |
| ! static int |
| ! DictionaryContains(DictionaryObject *self, PyObject *keyObject) |
| ! { |
| ! PyObject *rObj = _DictionaryItem(self, keyObject, DICT_FLAG_RETURN_BOOL); |
| ! int r; |
| ! |
| ! r = (rObj == Py_True); |
| ! |
| ! Py_DECREF(Py_True); |
| ! |
| ! return r; |
| ! } |
| ! |
| ! typedef struct |
| ! { |
| ! hashitem_T *ht_array; |
| ! long_u ht_used; |
| ! hashtab_T *ht; |
| ! hashitem_T *hi; |
| ! int todo; |
| ! } dictiterinfo_T; |
| ! |
| ! static PyObject * |
| ! DictionaryIterNext(dictiterinfo_T **dii) |
| ! { |
| ! PyObject *r; |
| ! |
| ! if (!(*dii)->todo) |
| ! return NULL; |
| ! |
| ! if ((*dii)->ht->ht_array != (*dii)->ht_array || |
| ! (*dii)->ht->ht_used != (*dii)->ht_used) |
| ! { |
| ! PyErr_SetString(PyExc_RuntimeError, |
| ! _("hashtab changed during iteration")); |
| ! return NULL; |
| ! } |
| ! |
| ! while (((*dii)->todo) && HASHITEM_EMPTY((*dii)->hi)) |
| ! ++((*dii)->hi); |
| ! |
| ! --((*dii)->todo); |
| ! |
| ! if (!(r = PyBytes_FromString((char *) (*dii)->hi->hi_key))) |
| ! return NULL; |
| ! |
| ! return r; |
| ! } |
| ! |
| ! static PyObject * |
| ! DictionaryIter(DictionaryObject *self) |
| ! { |
| ! dictiterinfo_T *dii; |
| ! hashtab_T *ht; |
| ! |
| ! if (!(dii = PyMem_New(dictiterinfo_T, 1))) |
| ! { |
| ! PyErr_NoMemory(); |
| ! return NULL; |
| ! } |
| ! |
| ! ht = &self->dict->dv_hashtab; |
| ! dii->ht_array = ht->ht_array; |
| ! dii->ht_used = ht->ht_used; |
| ! dii->ht = ht; |
| ! dii->hi = dii->ht_array; |
| ! dii->todo = dii->ht_used; |
| ! |
| ! return IterNew(dii, |
| ! (destructorfun) PyMem_Free, (nextfun) DictionaryIterNext, |
| ! NULL, NULL); |
| } |
| |
| static PyInt |
| |
| *** 1016,1033 **** |
| |
| if (di == NULL) |
| { |
| ! di = dictitem_alloc(key); |
| ! if (di == NULL) |
| { |
| PyErr_NoMemory(); |
| return -1; |
| } |
| di->di_tv.v_lock = 0; |
| |
| if (dict_add(dict, di) == FAIL) |
| { |
| DICTKEY_UNREF |
| vim_free(di); |
| PyErr_SetVim(_("failed to add key to dictionary")); |
| return -1; |
| } |
| --- 1209,1227 ---- |
| |
| if (di == NULL) |
| { |
| ! if (!(di = dictitem_alloc(key))) |
| { |
| PyErr_NoMemory(); |
| return -1; |
| } |
| di->di_tv.v_lock = 0; |
| + di->di_tv.v_type = VAR_UNKNOWN; |
| |
| if (dict_add(dict, di) == FAIL) |
| { |
| DICTKEY_UNREF |
| vim_free(di); |
| + dictitem_free(di); |
| PyErr_SetVim(_("failed to add key to dictionary")); |
| return -1; |
| } |
| |
| *** 1042,1062 **** |
| return 0; |
| } |
| |
| static PyObject * |
| ! DictionaryListKeys(DictionaryObject *self) |
| { |
| dict_T *dict = self->dict; |
| long_u todo = dict->dv_hashtab.ht_used; |
| Py_ssize_t i = 0; |
| PyObject *r; |
| hashitem_T *hi; |
| |
| r = PyList_New(todo); |
| for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi) |
| { |
| if (!HASHITEM_EMPTY(hi)) |
| { |
| ! PyList_SetItem(r, i, PyBytes_FromString((char *)(hi->hi_key))); |
| --todo; |
| ++i; |
| } |
| --- 1236,1269 ---- |
| return 0; |
| } |
| |
| + typedef PyObject *(*hi_to_py)(hashitem_T *); |
| + |
| static PyObject * |
| ! DictionaryListObjects(DictionaryObject *self, hi_to_py hiconvert) |
| { |
| dict_T *dict = self->dict; |
| long_u todo = dict->dv_hashtab.ht_used; |
| Py_ssize_t i = 0; |
| PyObject *r; |
| hashitem_T *hi; |
| + PyObject *newObj; |
| |
| r = PyList_New(todo); |
| for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi) |
| { |
| if (!HASHITEM_EMPTY(hi)) |
| { |
| ! if (!(newObj = hiconvert(hi))) |
| ! { |
| ! Py_DECREF(r); |
| ! return NULL; |
| ! } |
| ! if (PyList_SetItem(r, i, newObj)) |
| ! { |
| ! Py_DECREF(r); |
| ! Py_DECREF(newObj); |
| ! return NULL; |
| ! } |
| --todo; |
| ++i; |
| } |
| |
| *** 1064,1069 **** |
| --- 1271,1505 ---- |
| return r; |
| } |
| |
| + static PyObject * |
| + dict_key(hashitem_T *hi) |
| + { |
| + return PyBytes_FromString((char *)(hi->hi_key)); |
| + } |
| + |
| + static PyObject * |
| + DictionaryListKeys(DictionaryObject *self) |
| + { |
| + return DictionaryListObjects(self, dict_key); |
| + } |
| + |
| + static PyObject * |
| + dict_val(hashitem_T *hi) |
| + { |
| + dictitem_T *di; |
| + |
| + di = dict_lookup(hi); |
| + return ConvertToPyObject(&di->di_tv); |
| + } |
| + |
| + static PyObject * |
| + DictionaryListValues(DictionaryObject *self) |
| + { |
| + return DictionaryListObjects(self, dict_val); |
| + } |
| + |
| + static PyObject * |
| + dict_item(hashitem_T *hi) |
| + { |
| + PyObject *keyObject; |
| + PyObject *valObject; |
| + PyObject *r; |
| + |
| + if (!(keyObject = dict_key(hi))) |
| + return NULL; |
| + |
| + if (!(valObject = dict_val(hi))) |
| + { |
| + Py_DECREF(keyObject); |
| + return NULL; |
| + } |
| + |
| + r = Py_BuildValue("(OO)", keyObject, valObject); |
| + |
| + Py_DECREF(keyObject); |
| + Py_DECREF(valObject); |
| + |
| + return r; |
| + } |
| + |
| + static PyObject * |
| + DictionaryListItems(DictionaryObject *self) |
| + { |
| + return DictionaryListObjects(self, dict_item); |
| + } |
| + |
| + static PyObject * |
| + DictionaryUpdate(DictionaryObject *self, PyObject *args, PyObject *kwargs) |
| + { |
| + dict_T *dict = self->dict; |
| + |
| + if (dict->dv_lock) |
| + { |
| + PyErr_SetVim(_("dict is locked")); |
| + return NULL; |
| + } |
| + |
| + if (kwargs) |
| + { |
| + typval_T tv; |
| + |
| + if (ConvertFromPyMapping(kwargs, &tv) == -1) |
| + return NULL; |
| + |
| + VimTryStart(); |
| + dict_extend(self->dict, tv.vval.v_dict, (char_u *) "force"); |
| + clear_tv(&tv); |
| + if (VimTryEnd()) |
| + return NULL; |
| + } |
| + else |
| + { |
| + PyObject *object; |
| + |
| + if (!PyArg_Parse(args, "(O)", &object)) |
| + return NULL; |
| + |
| + if (PyObject_HasAttrString(object, "keys")) |
| + return DictionaryUpdate(self, NULL, object); |
| + else |
| + { |
| + PyObject *iterator; |
| + PyObject *item; |
| + |
| + if (!(iterator = PyObject_GetIter(object))) |
| + return NULL; |
| + |
| + while ((item = PyIter_Next(iterator))) |
| + { |
| + PyObject *fast; |
| + PyObject *keyObject; |
| + PyObject *valObject; |
| + PyObject *todecref; |
| + char_u *key; |
| + dictitem_T *di; |
| + |
| + if (!(fast = PySequence_Fast(item, ""))) |
| + { |
| + Py_DECREF(iterator); |
| + Py_DECREF(item); |
| + return NULL; |
| + } |
| + |
| + Py_DECREF(item); |
| + |
| + if (PySequence_Fast_GET_SIZE(fast) != 2) |
| + { |
| + Py_DECREF(iterator); |
| + Py_DECREF(fast); |
| + PyErr_SetString(PyExc_ValueError, |
| + _("expected sequence element of size 2")); |
| + return NULL; |
| + } |
| + |
| + keyObject = PySequence_Fast_GET_ITEM(fast, 0); |
| + |
| + if (!(key = StringToChars(keyObject, &todecref))) |
| + { |
| + Py_DECREF(iterator); |
| + Py_DECREF(fast); |
| + return NULL; |
| + } |
| + |
| + di = dictitem_alloc(key); |
| + |
| + Py_XDECREF(todecref); |
| + |
| + if (di == NULL) |
| + { |
| + Py_DECREF(fast); |
| + Py_DECREF(iterator); |
| + PyErr_NoMemory(); |
| + return NULL; |
| + } |
| + di->di_tv.v_lock = 0; |
| + di->di_tv.v_type = VAR_UNKNOWN; |
| + |
| + valObject = PySequence_Fast_GET_ITEM(fast, 1); |
| + |
| + if (ConvertFromPyObject(valObject, &di->di_tv) == -1) |
| + { |
| + Py_DECREF(iterator); |
| + Py_DECREF(fast); |
| + dictitem_free(di); |
| + return NULL; |
| + } |
| + |
| + Py_DECREF(fast); |
| + |
| + if (dict_add(dict, di) == FAIL) |
| + { |
| + Py_DECREF(iterator); |
| + dictitem_free(di); |
| + PyErr_SetVim(_("failed to add key to dictionary")); |
| + return NULL; |
| + } |
| + } |
| + |
| + Py_DECREF(iterator); |
| + |
| + /* Iterator may have finished due to an exception */ |
| + if (PyErr_Occurred()) |
| + return NULL; |
| + } |
| + } |
| + Py_INCREF(Py_None); |
| + return Py_None; |
| + } |
| + |
| + static PyObject * |
| + DictionaryGet(DictionaryObject *self, PyObject *args) |
| + { |
| + return _DictionaryItem(self, args, |
| + DICT_FLAG_HAS_DEFAULT|DICT_FLAG_NONE_DEFAULT); |
| + } |
| + |
| + static PyObject * |
| + DictionaryPop(DictionaryObject *self, PyObject *args) |
| + { |
| + return _DictionaryItem(self, args, DICT_FLAG_HAS_DEFAULT|DICT_FLAG_POP); |
| + } |
| + |
| + static PyObject * |
| + DictionaryPopItem(DictionaryObject *self, PyObject *args) |
| + { |
| + PyObject *keyObject; |
| + |
| + if (!PyArg_ParseTuple(args, "O", &keyObject)) |
| + return NULL; |
| + |
| + return _DictionaryItem(self, keyObject, |
| + DICT_FLAG_POP|DICT_FLAG_RETURN_PAIR); |
| + } |
| + |
| + static PyObject * |
| + DictionaryHasKey(DictionaryObject *self, PyObject *args) |
| + { |
| + PyObject *keyObject; |
| + |
| + if (!PyArg_ParseTuple(args, "O", &keyObject)) |
| + return NULL; |
| + |
| + return _DictionaryItem(self, keyObject, DICT_FLAG_RETURN_BOOL); |
| + } |
| + |
| + static PySequenceMethods DictionaryAsSeq = { |
| + 0, /* sq_length */ |
| + 0, /* sq_concat */ |
| + 0, /* sq_repeat */ |
| + 0, /* sq_item */ |
| + 0, /* sq_slice */ |
| + 0, /* sq_ass_item */ |
| + 0, /* sq_ass_slice */ |
| + (objobjproc) DictionaryContains, /* sq_contains */ |
| + 0, /* sq_inplace_concat */ |
| + 0, /* sq_inplace_repeat */ |
| + }; |
| + |
| static PyMappingMethods DictionaryAsMapping = { |
| (lenfunc) DictionaryLength, |
| (binaryfunc) DictionaryItem, |
| |
| *** 1072,1077 **** |
| --- 1508,1520 ---- |
| |
| static struct PyMethodDef DictionaryMethods[] = { |
| {"keys", (PyCFunction)DictionaryListKeys, METH_NOARGS, ""}, |
| + {"values", (PyCFunction)DictionaryListValues, METH_NOARGS, ""}, |
| + {"items", (PyCFunction)DictionaryListItems, METH_NOARGS, ""}, |
| + {"update", (PyCFunction)DictionaryUpdate, METH_VARARGS|METH_KEYWORDS, ""}, |
| + {"get", (PyCFunction)DictionaryGet, METH_VARARGS, ""}, |
| + {"pop", (PyCFunction)DictionaryPop, METH_VARARGS, ""}, |
| + {"popitem", (PyCFunction)DictionaryPopItem, METH_VARARGS, ""}, |
| + {"has_key", (PyCFunction)DictionaryHasKey, METH_VARARGS, ""}, |
| {"__dir__", (PyCFunction)DictionaryDir, METH_NOARGS, ""}, |
| { NULL, NULL, 0, NULL} |
| }; |
| |
| *** 1541,1554 **** |
| selfdictObject = PyDict_GetItemString(kwargs, "self"); |
| if (selfdictObject != NULL) |
| { |
| ! if (!PyMapping_Check(selfdictObject)) |
| ! { |
| ! PyErr_SetString(PyExc_TypeError, |
| ! _("'self' argument must be a dictionary")); |
| ! clear_tv(&args); |
| ! return NULL; |
| ! } |
| ! if (ConvertFromPyObject(selfdictObject, &selfdicttv) == -1) |
| { |
| clear_tv(&args); |
| return NULL; |
| --- 1984,1990 ---- |
| selfdictObject = PyDict_GetItemString(kwargs, "self"); |
| if (selfdictObject != NULL) |
| { |
| ! if (ConvertFromPyMapping(selfdictObject, &selfdicttv) == -1) |
| { |
| clear_tv(&args); |
| return NULL; |
| |
| *** 1994,2000 **** |
| else if (strcmp(name, "number") == 0) |
| return PyLong_FromLong((long) get_tab_number(self->tab)); |
| else if (strcmp(name, "vars") == 0) |
| ! return DictionaryNew(self->tab->tp_vars); |
| else if (strcmp(name, "window") == 0) |
| { |
| /* For current tab window.c does not bother to set or update tp_curwin |
| --- 2430,2436 ---- |
| else if (strcmp(name, "number") == 0) |
| return PyLong_FromLong((long) get_tab_number(self->tab)); |
| else if (strcmp(name, "vars") == 0) |
| ! return NEW_DICTIONARY(self->tab->tp_vars); |
| else if (strcmp(name, "window") == 0) |
| { |
| /* For current tab window.c does not bother to set or update tp_curwin |
| |
| *** 2225,2231 **** |
| return PyLong_FromLong((long)(W_WINCOL(self->win))); |
| #endif |
| else if (strcmp(name, "vars") == 0) |
| ! return DictionaryNew(self->win->w_vars); |
| else if (strcmp(name, "options") == 0) |
| return OptionsNew(SREQ_WIN, self->win, (checkfun) CheckWindow, |
| (PyObject *) self); |
| --- 2661,2667 ---- |
| return PyLong_FromLong((long)(W_WINCOL(self->win))); |
| #endif |
| else if (strcmp(name, "vars") == 0) |
| ! return NEW_DICTIONARY(self->win->w_vars); |
| else if (strcmp(name, "options") == 0) |
| return OptionsNew(SREQ_WIN, self->win, (checkfun) CheckWindow, |
| (PyObject *) self); |
| |
| *** 3402,3408 **** |
| else if (strcmp(name, "number") == 0) |
| return Py_BuildValue(Py_ssize_t_fmt, self->buf->b_fnum); |
| else if (strcmp(name, "vars") == 0) |
| ! return DictionaryNew(self->buf->b_vars); |
| else if (strcmp(name, "options") == 0) |
| return OptionsNew(SREQ_BUF, self->buf, (checkfun) CheckBuffer, |
| (PyObject *) self); |
| --- 3838,3844 ---- |
| else if (strcmp(name, "number") == 0) |
| return Py_BuildValue(Py_ssize_t_fmt, self->buf->b_fnum); |
| else if (strcmp(name, "vars") == 0) |
| ! return NEW_DICTIONARY(self->buf->b_vars); |
| else if (strcmp(name, "options") == 0) |
| return OptionsNew(SREQ_BUF, self->buf, (checkfun) CheckBuffer, |
| (PyObject *) self); |
| |
| *** 4307,4312 **** |
| --- 4743,4778 ---- |
| } |
| |
| static int |
| + ConvertFromPyMapping(PyObject *obj, typval_T *tv) |
| + { |
| + PyObject *lookup_dict; |
| + int r; |
| + |
| + if (!(lookup_dict = PyDict_New())) |
| + return -1; |
| + |
| + if (PyType_IsSubtype(obj->ob_type, &DictionaryType)) |
| + { |
| + tv->v_type = VAR_DICT; |
| + tv->vval.v_dict = (((DictionaryObject *)(obj))->dict); |
| + ++tv->vval.v_dict->dv_refcount; |
| + r = 0; |
| + } |
| + else if (PyDict_Check(obj)) |
| + r = convert_dl(obj, tv, pydict_to_tv, lookup_dict); |
| + else if (PyMapping_Check(obj)) |
| + r = convert_dl(obj, tv, pymap_to_tv, lookup_dict); |
| + else |
| + { |
| + PyErr_SetString(PyExc_TypeError, |
| + _("unable to convert object to vim dictionary")); |
| + r = -1; |
| + } |
| + Py_DECREF(lookup_dict); |
| + return r; |
| + } |
| + |
| + static int |
| ConvertFromPyObject(PyObject *obj, typval_T *tv) |
| { |
| PyObject *lookup_dict; |
| |
| *** 4322,4328 **** |
| static int |
| _ConvertFromPyObject(PyObject *obj, typval_T *tv, PyObject *lookup_dict) |
| { |
| ! if (obj->ob_type == &DictionaryType) |
| { |
| tv->v_type = VAR_DICT; |
| tv->vval.v_dict = (((DictionaryObject *)(obj))->dict); |
| --- 4788,4794 ---- |
| static int |
| _ConvertFromPyObject(PyObject *obj, typval_T *tv, PyObject *lookup_dict) |
| { |
| ! if (PyType_IsSubtype(obj->ob_type, &DictionaryType)) |
| { |
| tv->v_type = VAR_DICT; |
| tv->vval.v_dict = (((DictionaryObject *)(obj))->dict); |
| |
| *** 4437,4443 **** |
| case VAR_LIST: |
| return ListNew(tv->vval.v_list); |
| case VAR_DICT: |
| ! return DictionaryNew(tv->vval.v_dict); |
| case VAR_FUNC: |
| return FunctionNew(tv->vval.v_string == NULL |
| ? (char_u *)"" : tv->vval.v_string); |
| --- 4903,4909 ---- |
| case VAR_LIST: |
| return ListNew(tv->vval.v_list); |
| case VAR_DICT: |
| ! return NEW_DICTIONARY(tv->vval.v_dict); |
| case VAR_FUNC: |
| return FunctionNew(tv->vval.v_string == NULL |
| ? (char_u *)"" : tv->vval.v_string); |
| |
| *** 4608,4617 **** |
| DictionaryType.tp_name = "vim.dictionary"; |
| DictionaryType.tp_basicsize = sizeof(DictionaryObject); |
| DictionaryType.tp_dealloc = (destructor)DictionaryDestructor; |
| DictionaryType.tp_as_mapping = &DictionaryAsMapping; |
| ! DictionaryType.tp_flags = Py_TPFLAGS_DEFAULT; |
| DictionaryType.tp_doc = "dictionary pushing modifications to vim structure"; |
| DictionaryType.tp_methods = DictionaryMethods; |
| #if PY_MAJOR_VERSION >= 3 |
| DictionaryType.tp_getattro = (getattrofunc)DictionaryGetattro; |
| DictionaryType.tp_setattro = (setattrofunc)DictionarySetattro; |
| --- 5074,5087 ---- |
| DictionaryType.tp_name = "vim.dictionary"; |
| DictionaryType.tp_basicsize = sizeof(DictionaryObject); |
| DictionaryType.tp_dealloc = (destructor)DictionaryDestructor; |
| + DictionaryType.tp_as_sequence = &DictionaryAsSeq; |
| DictionaryType.tp_as_mapping = &DictionaryAsMapping; |
| ! DictionaryType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE; |
| DictionaryType.tp_doc = "dictionary pushing modifications to vim structure"; |
| DictionaryType.tp_methods = DictionaryMethods; |
| + DictionaryType.tp_iter = (getiterfunc)DictionaryIter; |
| + DictionaryType.tp_new = (newfunc)DictionaryConstructor; |
| + DictionaryType.tp_alloc = (allocfunc)PyType_GenericAlloc; |
| #if PY_MAJOR_VERSION >= 3 |
| DictionaryType.tp_getattro = (getattrofunc)DictionaryGetattro; |
| DictionaryType.tp_setattro = (setattrofunc)DictionarySetattro; |
| |
| *** 4786,4793 **** |
| return -1; |
| ADD_OBJECT(m, "error", VimError); |
| |
| ! ADD_CHECKED_OBJECT(m, "vars", DictionaryNew(&globvardict)); |
| ! ADD_CHECKED_OBJECT(m, "vvars", DictionaryNew(&vimvardict)); |
| ADD_CHECKED_OBJECT(m, "options", |
| OptionsNew(SREQ_GLOBAL, NULL, dummy_check, NULL)); |
| return 0; |
| --- 5256,5263 ---- |
| return -1; |
| ADD_OBJECT(m, "error", VimError); |
| |
| ! ADD_CHECKED_OBJECT(m, "vars", NEW_DICTIONARY(&globvardict)); |
| ! ADD_CHECKED_OBJECT(m, "vvars", NEW_DICTIONARY(&vimvardict)); |
| ADD_CHECKED_OBJECT(m, "options", |
| OptionsNew(SREQ_GLOBAL, NULL, dummy_check, NULL)); |
| return 0; |
| |
| |
| |
| *** 96,101 **** |
| --- 96,102 ---- |
| #define PyInt_FromLong(i) PyLong_FromLong(i) |
| #define PyInt_AsLong(obj) PyLong_AsLong(obj) |
| #define Py_ssize_t_fmt "n" |
| + #define Py_bytes_fmt "y" |
| |
| #if defined(DYNAMIC_PYTHON3) || defined(PROTO) |
| |
| |
| *** 149,154 **** |
| --- 150,156 ---- |
| # define PySequence_Check py3_PySequence_Check |
| # define PySequence_Size py3_PySequence_Size |
| # define PySequence_GetItem py3_PySequence_GetItem |
| + # define PySequence_Fast py3_PySequence_Fast |
| # define PyTuple_Size py3_PyTuple_Size |
| # define PyTuple_GetItem py3_PyTuple_GetItem |
| # define PySlice_GetIndicesEx py3_PySlice_GetIndicesEx |
| |
| *** 168,173 **** |
| --- 170,176 ---- |
| #undef PyRun_String |
| # define PyRun_String py3_PyRun_String |
| # define PyObject_GetAttrString py3_PyObject_GetAttrString |
| + # define PyObject_HasAttrString py3_PyObject_HasAttrString |
| # define PyObject_SetAttrString py3_PyObject_SetAttrString |
| # define PyObject_CallFunctionObjArgs py3_PyObject_CallFunctionObjArgs |
| # define PyEval_GetLocals py3_PyEval_GetLocals |
| |
| *** 269,274 **** |
| --- 272,278 ---- |
| static int (*py3_PySequence_Check)(PyObject *); |
| static Py_ssize_t (*py3_PySequence_Size)(PyObject *); |
| static PyObject* (*py3_PySequence_GetItem)(PyObject *, Py_ssize_t); |
| + static PyObject* (*py3_PySequence_Fast)(PyObject *, const char *); |
| static Py_ssize_t (*py3_PyTuple_Size)(PyObject *); |
| static PyObject* (*py3_PyTuple_GetItem)(PyObject *, Py_ssize_t); |
| static int (*py3_PyMapping_Check)(PyObject *); |
| |
| *** 282,287 **** |
| --- 286,292 ---- |
| static int (*py3_PyRun_SimpleString)(char *); |
| static PyObject* (*py3_PyRun_String)(char *, int, PyObject *, PyObject *); |
| static PyObject* (*py3_PyObject_GetAttrString)(PyObject *, const char *); |
| + static int (*py3_PyObject_HasAttrString)(PyObject *, const char *); |
| static PyObject* (*py3_PyObject_SetAttrString)(PyObject *, const char *, PyObject *); |
| static PyObject* (*py3_PyObject_CallFunctionObjArgs)(PyObject *, ...); |
| static PyObject* (*py3_PyEval_GetGlobals)(); |
| |
| *** 425,430 **** |
| --- 430,436 ---- |
| {"PySequence_Check", (PYTHON_PROC*)&py3_PySequence_Check}, |
| {"PySequence_Size", (PYTHON_PROC*)&py3_PySequence_Size}, |
| {"PySequence_GetItem", (PYTHON_PROC*)&py3_PySequence_GetItem}, |
| + {"PySequence_Fast", (PYTHON_PROC*)&py3_PySequence_Fast}, |
| {"PyTuple_Size", (PYTHON_PROC*)&py3_PyTuple_Size}, |
| {"PyTuple_GetItem", (PYTHON_PROC*)&py3_PyTuple_GetItem}, |
| {"PySlice_GetIndicesEx", (PYTHON_PROC*)&py3_PySlice_GetIndicesEx}, |
| |
| *** 435,440 **** |
| --- 441,447 ---- |
| {"PyRun_SimpleString", (PYTHON_PROC*)&py3_PyRun_SimpleString}, |
| {"PyRun_String", (PYTHON_PROC*)&py3_PyRun_String}, |
| {"PyObject_GetAttrString", (PYTHON_PROC*)&py3_PyObject_GetAttrString}, |
| + {"PyObject_HasAttrString", (PYTHON_PROC*)&py3_PyObject_HasAttrString}, |
| {"PyObject_SetAttrString", (PYTHON_PROC*)&py3_PyObject_SetAttrString}, |
| {"PyObject_CallFunctionObjArgs", (PYTHON_PROC*)&py3_PyObject_CallFunctionObjArgs}, |
| {"PyEval_GetGlobals", (PYTHON_PROC*)&py3_PyEval_GetGlobals}, |
| |
| |
| |
| *** 103,108 **** |
| --- 103,109 ---- |
| # define PyIntIntObjArgProc intintobjargproc |
| # define Py_ssize_t_fmt "i" |
| #endif |
| + #define Py_bytes_fmt "s" |
| |
| /* Parser flags */ |
| #define single_input 256 |
| |
| *** 187,192 **** |
| --- 188,194 ---- |
| # define PySequence_Check dll_PySequence_Check |
| # define PySequence_Size dll_PySequence_Size |
| # define PySequence_GetItem dll_PySequence_GetItem |
| + # define PySequence_Fast dll_PySequence_Fast |
| # define PyTuple_Size dll_PyTuple_Size |
| # define PyTuple_GetItem dll_PyTuple_GetItem |
| # define PyTuple_Type (*dll_PyTuple_Type) |
| |
| *** 207,212 **** |
| --- 209,215 ---- |
| # define PyRun_SimpleString dll_PyRun_SimpleString |
| # define PyRun_String dll_PyRun_String |
| # define PyObject_GetAttrString dll_PyObject_GetAttrString |
| + # define PyObject_HasAttrString dll_PyObject_HasAttrString |
| # define PyObject_SetAttrString dll_PyObject_SetAttrString |
| # define PyObject_CallFunctionObjArgs dll_PyObject_CallFunctionObjArgs |
| # define PyString_AsString dll_PyString_AsString |
| |
| *** 227,232 **** |
| --- 230,236 ---- |
| # define PySys_SetArgv dll_PySys_SetArgv |
| # define PyType_Type (*dll_PyType_Type) |
| # define PyType_Ready (*dll_PyType_Ready) |
| + # define PyType_GenericAlloc dll_PyType_GenericAlloc |
| # define Py_BuildValue dll_Py_BuildValue |
| # define Py_FindMethod dll_Py_FindMethod |
| # define Py_InitModule4 dll_Py_InitModule4 |
| |
| *** 318,323 **** |
| --- 322,328 ---- |
| static int (*dll_PySequence_Check)(PyObject *); |
| static PyInt(*dll_PySequence_Size)(PyObject *); |
| static PyObject*(*dll_PySequence_GetItem)(PyObject *, PyInt); |
| + static PyObject*(*dll_PySequence_Fast)(PyObject *, const char *); |
| static PyInt(*dll_PyTuple_Size)(PyObject *); |
| static PyObject*(*dll_PyTuple_GetItem)(PyObject *, PyInt); |
| static PyTypeObject* dll_PyTuple_Type; |
| |
| *** 336,341 **** |
| --- 341,347 ---- |
| static int(*dll_PyRun_SimpleString)(char *); |
| static PyObject *(*dll_PyRun_String)(char *, int, PyObject *, PyObject *); |
| static PyObject* (*dll_PyObject_GetAttrString)(PyObject *, const char *); |
| + static int (*dll_PyObject_HasAttrString)(PyObject *, const char *); |
| static PyObject* (*dll_PyObject_SetAttrString)(PyObject *, const char *, PyObject *); |
| static PyObject* (*dll_PyObject_CallFunctionObjArgs)(PyObject *, ...); |
| static char*(*dll_PyString_AsString)(PyObject *); |
| |
| *** 354,359 **** |
| --- 360,366 ---- |
| static int(*dll_PySys_SetArgv)(int, char **); |
| static PyTypeObject* dll_PyType_Type; |
| static int (*dll_PyType_Ready)(PyTypeObject *type); |
| + static PyObject* (*dll_PyType_GenericAlloc)(PyTypeObject *type, PyInt nitems); |
| static PyObject*(*dll_Py_BuildValue)(char *, ...); |
| static PyObject*(*dll_Py_FindMethod)(struct PyMethodDef[], PyObject *, char *); |
| static PyObject*(*dll_Py_InitModule4)(char *, struct PyMethodDef *, char *, PyObject *, int); |
| |
| *** 475,483 **** |
| {"PyList_SetItem", (PYTHON_PROC*)&dll_PyList_SetItem}, |
| {"PyList_Size", (PYTHON_PROC*)&dll_PyList_Size}, |
| {"PyList_Type", (PYTHON_PROC*)&dll_PyList_Type}, |
| - {"PySequence_GetItem", (PYTHON_PROC*)&dll_PySequence_GetItem}, |
| {"PySequence_Size", (PYTHON_PROC*)&dll_PySequence_Size}, |
| {"PySequence_Check", (PYTHON_PROC*)&dll_PySequence_Check}, |
| {"PyTuple_GetItem", (PYTHON_PROC*)&dll_PyTuple_GetItem}, |
| {"PyTuple_Size", (PYTHON_PROC*)&dll_PyTuple_Size}, |
| {"PyTuple_Type", (PYTHON_PROC*)&dll_PyTuple_Type}, |
| --- 482,491 ---- |
| {"PyList_SetItem", (PYTHON_PROC*)&dll_PyList_SetItem}, |
| {"PyList_Size", (PYTHON_PROC*)&dll_PyList_Size}, |
| {"PyList_Type", (PYTHON_PROC*)&dll_PyList_Type}, |
| {"PySequence_Size", (PYTHON_PROC*)&dll_PySequence_Size}, |
| {"PySequence_Check", (PYTHON_PROC*)&dll_PySequence_Check}, |
| + {"PySequence_GetItem", (PYTHON_PROC*)&dll_PySequence_GetItem}, |
| + {"PySequence_Fast", (PYTHON_PROC*)&dll_PySequence_Fast}, |
| {"PyTuple_GetItem", (PYTHON_PROC*)&dll_PyTuple_GetItem}, |
| {"PyTuple_Size", (PYTHON_PROC*)&dll_PyTuple_Size}, |
| {"PyTuple_Type", (PYTHON_PROC*)&dll_PyTuple_Type}, |
| |
| *** 496,501 **** |
| --- 504,510 ---- |
| {"PyRun_SimpleString", (PYTHON_PROC*)&dll_PyRun_SimpleString}, |
| {"PyRun_String", (PYTHON_PROC*)&dll_PyRun_String}, |
| {"PyObject_GetAttrString", (PYTHON_PROC*)&dll_PyObject_GetAttrString}, |
| + {"PyObject_HasAttrString", (PYTHON_PROC*)&dll_PyObject_HasAttrString}, |
| {"PyObject_SetAttrString", (PYTHON_PROC*)&dll_PyObject_SetAttrString}, |
| {"PyObject_CallFunctionObjArgs", (PYTHON_PROC*)&dll_PyObject_CallFunctionObjArgs}, |
| {"PyString_AsString", (PYTHON_PROC*)&dll_PyString_AsString}, |
| |
| *** 514,519 **** |
| --- 523,529 ---- |
| {"PySys_SetArgv", (PYTHON_PROC*)&dll_PySys_SetArgv}, |
| {"PyType_Type", (PYTHON_PROC*)&dll_PyType_Type}, |
| {"PyType_Ready", (PYTHON_PROC*)&dll_PyType_Ready}, |
| + {"PyType_GenericAlloc", (PYTHON_PROC*)&dll_PyType_GenericAlloc}, |
| {"Py_FindMethod", (PYTHON_PROC*)&dll_Py_FindMethod}, |
| {"Py_SetPythonHome", (PYTHON_PROC*)&dll_Py_SetPythonHome}, |
| {"Py_Initialize", (PYTHON_PROC*)&dll_Py_Initialize}, |
| |
| *** 1116,1125 **** |
| (PyIntObjArgProc) BufferAssItem, /* sq_ass_item, x[i]=v */ |
| (PyIntIntObjArgProc) BufferAssSlice, /* sq_ass_slice, x[i:j]=v */ |
| (objobjproc) 0, |
| - #if PY_MAJOR_VERSION >= 2 |
| (binaryfunc) 0, |
| 0, |
| - #endif |
| }; |
| |
| /* Buffer object - Implementation |
| --- 1126,1133 ---- |
| |
| |
| |
| *** 75,80 **** |
| --- 75,81 ---- |
| dictitem_T *dict_find __ARGS((dict_T *d, char_u *key, int len)); |
| char_u *get_dict_string __ARGS((dict_T *d, char_u *key, int save)); |
| long get_dict_number __ARGS((dict_T *d, char_u *key)); |
| + void dict_extend __ARGS((dict_T *d1, dict_T *d2, char_u *action)); |
| char_u *get_function_name __ARGS((expand_T *xp, int idx)); |
| char_u *get_expr_name __ARGS((expand_T *xp, int idx)); |
| char_u *get_expanded_name __ARGS((char_u *name, int check)); |
| |
| |
| |
| *** 31,46 **** |
| :" |
| :" Extending Dictionary directly with different types |
| :let d = {} |
| ! :py d=vim.bindeval('d') |
| ! :py d['1']='asd' |
| ! :py d['b']=[1, 2, f] |
| ! :py d['-1']={'a': 1} |
| ! :let dkeys = [] |
| ! :py dk=vim.bindeval('dkeys') |
| ! :py dkeys=d.keys() |
| ! :py dkeys.sort() |
| ! :py dk.extend(dkeys) |
| ! :$put =string(dkeys) |
| :for [key, val] in sort(items(d)) |
| : $put =string(key) . ' : ' . string(val) |
| : unlet key val |
| --- 31,52 ---- |
| :" |
| :" Extending Dictionary directly with different types |
| :let d = {} |
| ! py << EOF |
| ! d=vim.bindeval('d') |
| ! d['1']='asd' |
| ! d.update(b=[1, 2, f]) |
| ! d.update((('-1', {'a': 1}),)) |
| ! d.update({'0': -1}) |
| ! dk = d.keys() |
| ! dv = d.values() |
| ! di = d.items() |
| ! dk.sort(key=repr) |
| ! dv.sort(key=repr) |
| ! di.sort(key=repr) |
| ! EOF |
| ! :$put =pyeval('repr(dk)') |
| ! :$put =substitute(pyeval('repr(dv)'),'0x\x\+','','g') |
| ! :$put =substitute(pyeval('repr(di)'),'0x\x\+','','g') |
| :for [key, val] in sort(items(d)) |
| : $put =string(key) . ' : ' . string(val) |
| : unlet key val |
| |
| *** 60,66 **** |
| --- 66,85 ---- |
| :$put =string(l) |
| :" |
| :py del d['-1'] |
| + :$put =string(pyeval('d.get(''b'', 1)')) |
| + :$put =string(pyeval('d.pop(''b'')')) |
| + :$put =string(pyeval('d.get(''b'', 1)')) |
| + :$put =string(pyeval('d.pop(''1'', 2)')) |
| + :$put =string(pyeval('d.pop(''1'', 2)')) |
| + :$put =pyeval('repr(d.has_key(''0''))') |
| + :$put =pyeval('repr(d.has_key(''1''))') |
| + :$put =pyeval('repr(''0'' in d)') |
| + :$put =pyeval('repr(''1'' in d)') |
| + :$put =pyeval('repr(list(iter(d)))') |
| :$put =string(d) |
| + :$put =pyeval('repr(d.popitem(''0''))') |
| + :$put =pyeval('repr(d.get(''0''))') |
| + :$put =pyeval('repr(list(iter(d)))') |
| :" |
| :" removing items out of range: silently skip items that don't exist |
| :let l = [0, 1, 2, 3] |
| |
| *** 198,203 **** |
| --- 217,225 ---- |
| em('d[""]=1') |
| em('d["a\\0b"]=1') |
| em('d[u"a\\0b"]=1') |
| + |
| + em('d.pop("abc")') |
| + em('d.popitem("abc")') |
| EOF |
| :$put =messages |
| :unlet messages |
| |
| *** 709,714 **** |
| --- 731,740 ---- |
| del o |
| EOF |
| :" |
| + :" Test vim.*.__new__ |
| + :$put =string(pyeval('vim.Dictionary({})')) |
| + :$put =string(pyeval('vim.Dictionary(a=1)')) |
| + :$put =string(pyeval('vim.Dictionary(((''a'', 1),))')) |
| :" |
| :" Test stdout/stderr |
| :redir => messages |
| |
| *** 718,723 **** |
| --- 744,759 ---- |
| :py sys.stderr.writelines(iter('abc')) |
| :redir END |
| :$put =string(substitute(messages, '\d\+', '', 'g')) |
| + :" Test subclassing |
| + py << EOF |
| + class DupDict(vim.Dictionary): |
| + def __setitem__(self, key, value): |
| + super(DupDict, self).__setitem__(key, value) |
| + super(DupDict, self).__setitem__('dup_' + key, value) |
| + dd = DupDict() |
| + dd['a'] = 'b' |
| + EOF |
| + :$put =string(sort(keys(pyeval('dd')))) |
| :" |
| :" Test exceptions |
| :fun Exe(e) |
| |
| |
| |
| *** 4,16 **** |
| Vim(put):E684: |
| [0, 'as''d', [1, 2, function('strlen'), {'a': 1}]] |
| [0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]] |
| ! ['-1', '1', 'b'] |
| '-1' : {'a': 1} |
| '1' : 'asd' |
| 'b' : [1, 2, function('strlen')] |
| [0, function('strlen')] |
| [3] |
| ! {'1': 'asd', 'b': [1, 2, function('strlen')]} |
| [0, 1, 2, 3] |
| [0, 1, 2, 3] |
| [0, 1, 3] |
| --- 4,32 ---- |
| Vim(put):E684: |
| [0, 'as''d', [1, 2, function('strlen'), {'a': 1}]] |
| [0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]] |
| ! ['-1', '0', '1', 'b'] |
| ! ['asd', -1L, <vim.dictionary object at >, <vim.list object at >] |
| ! [('-1', <vim.dictionary object at >), ('0', -1L), ('1', 'asd'), ('b', <vim.list object at >)] |
| '-1' : {'a': 1} |
| + '0' : -1 |
| '1' : 'asd' |
| 'b' : [1, 2, function('strlen')] |
| [0, function('strlen')] |
| [3] |
| ! [1, 2, function('strlen')] |
| ! [1, 2, function('strlen')] |
| ! 1 |
| ! 'asd' |
| ! 2 |
| ! True |
| ! False |
| ! True |
| ! False |
| ! ['0'] |
| ! {'0': -1} |
| ! ('', -1L) |
| ! None |
| ! [] |
| [0, 1, 2, 3] |
| [0, 1, 2, 3] |
| [0, 1, 3] |
| |
| *** 44,49 **** |
| --- 60,67 ---- |
| ValueError |
| TypeError |
| TypeError |
| + KeyError |
| + KeyError |
| d : locked:0;scope:0 |
| dl : locked:1;scope:0 |
| v: : locked:2;scope:1 |
| |
| *** 387,396 **** |
| window:__dir__,__members__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars |
| tabpage:__dir__,__members__,number,valid,vars,window,windows |
| range:__dir__,__members__,append,end,start |
| ! dictionary:__dir__,__members__,keys,locked,scope |
| list:__dir__,__members__,extend,locked |
| function:__call__,__dir__,__members__,softspace |
| output:__dir__,__members__,flush,softspace,write,writelines |
| ' |
| abcdef |
| line : |
| --- 405,417 ---- |
| window:__dir__,__members__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars |
| tabpage:__dir__,__members__,number,valid,vars,window,windows |
| range:__dir__,__members__,append,end,start |
| ! dictionary:__dir__,__members__,get,has_key,items,keys,locked,pop,popitem,scope,update,values |
| list:__dir__,__members__,extend,locked |
| function:__call__,__dir__,__members__,softspace |
| output:__dir__,__members__,flush,softspace,write,writelines |
| + {} |
| + {'a': 1} |
| + {'a': 1} |
| ' |
| abcdef |
| line : |
| |
| *** 398,403 **** |
| --- 419,425 ---- |
| abc |
| line : |
| abc' |
| + ['a', 'dup_a'] |
| (<class 'vim.error'>, error('abc',)) |
| (<class 'vim.error'>, error('def',)) |
| (<class 'vim.error'>, error('ghi',)) |
| |
| |
| |
| *** 26,41 **** |
| :" |
| :" Extending Dictionary directly with different types |
| :let d = {} |
| ! :py3 d=vim.bindeval('d') |
| ! :py3 d['1']='asd' |
| ! :py3 d['b']=[1, 2, f] |
| ! :py3 d['-1']={'a': 1} |
| ! :let dkeys = [] |
| ! :py3 dk=vim.bindeval('dkeys') |
| ! :py3 dkeys=d.keys() |
| ! :py3 dkeys.sort() |
| ! :py3 dk+=dkeys |
| ! :$put =string(dkeys) |
| :for [key, val] in sort(items(d)) |
| : $put =string(key) . ' : ' . string(val) |
| : unlet key val |
| --- 26,47 ---- |
| :" |
| :" Extending Dictionary directly with different types |
| :let d = {} |
| ! py3 << EOF |
| ! d=vim.bindeval('d') |
| ! d['1']='asd' |
| ! d.update(b=[1, 2, f]) |
| ! d.update((('-1', {'a': 1}),)) |
| ! d.update({'0': -1}) |
| ! dk = d.keys() |
| ! dv = d.values() |
| ! di = d.items() |
| ! dk.sort(key=repr) |
| ! dv.sort(key=repr) |
| ! di.sort(key=repr) |
| ! EOF |
| ! :$put =py3eval('repr(dk)') |
| ! :$put =substitute(py3eval('repr(dv)'),'0x\x\+','','g') |
| ! :$put =substitute(py3eval('repr(di)'),'0x\x\+','','g') |
| :for [key, val] in sort(items(d)) |
| : $put =string(key) . ' : ' . string(val) |
| : unlet key val |
| |
| *** 55,61 **** |
| --- 61,80 ---- |
| :$put =string(l) |
| :" |
| :py3 del d['-1'] |
| + :$put =string(py3eval('d.get(''b'', 1)')) |
| + :$put =string(py3eval('d.pop(''b'')')) |
| + :$put =string(py3eval('d.get(''b'', 1)')) |
| + :$put =string(py3eval('d.pop(''1'', 2)')) |
| + :$put =string(py3eval('d.pop(''1'', 2)')) |
| + :$put =py3eval('repr(d.has_key(''0''))') |
| + :$put =py3eval('repr(d.has_key(''1''))') |
| + :$put =py3eval('repr(''0'' in d)') |
| + :$put =py3eval('repr(''1'' in d)') |
| + :$put =py3eval('repr(list(iter(d)))') |
| :$put =string(d) |
| + :$put =py3eval('repr(d.popitem(''0''))') |
| + :$put =py3eval('repr(d.get(''0''))') |
| + :$put =py3eval('repr(list(iter(d)))') |
| :" |
| :" removing items out of range: silently skip items that don't exist |
| :let l = [0, 1, 2, 3] |
| |
| *** 181,215 **** |
| :py3 <<EOF |
| d=vim.bindeval('{}') |
| m=vim.bindeval('messages') |
| ! try: |
| ! d['abc'] |
| ! except Exception as e: |
| ! m.extend([e.__class__.__name__]) |
| ! |
| ! try: |
| ! d['abc']="\0" |
| ! except Exception as e: |
| ! m.extend([e.__class__.__name__]) |
| ! |
| ! try: |
| ! d['abc']=vim |
| ! except Exception as e: |
| ! m.extend([e.__class__.__name__]) |
| ! |
| ! try: |
| ! d['']=1 |
| ! except Exception as e: |
| ! m.extend([e.__class__.__name__]) |
| |
| ! try: |
| ! d['a\0b']=1 |
| ! except Exception as e: |
| ! m.extend([e.__class__.__name__]) |
| |
| ! try: |
| ! d[b'a\0b']=1 |
| ! except Exception as e: |
| ! m.extend([e.__class__.__name__]) |
| EOF |
| :$put =messages |
| :unlet messages |
| --- 200,220 ---- |
| :py3 <<EOF |
| d=vim.bindeval('{}') |
| m=vim.bindeval('messages') |
| ! def em(expr, g=globals(), l=locals()): |
| ! try: |
| ! exec(expr, g, l) |
| ! except Exception as e: |
| ! m.extend([e.__class__.__name__]) |
| |
| ! em('d["abc"]') |
| ! em('d["abc"]="\\0"') |
| ! em('d["abc"]=vim') |
| ! em('d[""]=1') |
| ! em('d["a\\0b"]=1') |
| ! em('d[b"a\\0b"]=1') |
| |
| ! em('d.pop("abc")') |
| ! em('d.popitem("abc")') |
| EOF |
| :$put =messages |
| :unlet messages |
| |
| *** 687,692 **** |
| --- 692,701 ---- |
| del o |
| EOF |
| :" |
| + :" Test vim.Dictionary.__new__ |
| + :$put =string(py3eval('vim.Dictionary({})')) |
| + :$put =string(py3eval('vim.Dictionary(a=1)')) |
| + :$put =string(py3eval('vim.Dictionary(((''a'', 1),))')) |
| :" |
| :" Test stdout/stderr |
| :redir => messages |
| |
| *** 696,701 **** |
| --- 705,720 ---- |
| :py sys.stderr.writelines(iter('abc')) |
| :redir END |
| :$put =string(substitute(messages, '\d\+', '', 'g')) |
| + :" Test subclassing |
| + py3 << EOF |
| + class DupDict(vim.Dictionary): |
| + def __setitem__(self, key, value): |
| + super(DupDict, self).__setitem__(key, value) |
| + super(DupDict, self).__setitem__('dup_' + key, value) |
| + dd = DupDict() |
| + dd['a'] = 'b' |
| + EOF |
| + :$put =string(sort(keys(py3eval('dd')))) |
| :" |
| :" Test exceptions |
| :fun Exe(e) |
| |
| |
| |
| *** 4,16 **** |
| Vim(put):E684: |
| [0, 'as''d', [1, 2, function('strlen'), {'a': 1}]] |
| [0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]] |
| ! ['-1', '1', 'b'] |
| '-1' : {'a': 1} |
| '1' : 'asd' |
| 'b' : [1, 2, function('strlen')] |
| [0, function('strlen')] |
| [3] |
| ! {'1': 'asd', 'b': [1, 2, function('strlen')]} |
| [0, 1, 2, 3] |
| [0, 1, 2, 3] |
| [0, 1, 3] |
| --- 4,32 ---- |
| Vim(put):E684: |
| [0, 'as''d', [1, 2, function('strlen'), {'a': 1}]] |
| [0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]] |
| ! [b'-1', b'0', b'1', b'b'] |
| ! [-1, <vim.dictionary object at >, <vim.list object at >, b'asd'] |
| ! [(b'-1', <vim.dictionary object at >), (b'0', -1), (b'1', b'asd'), (b'b', <vim.list object at >)] |
| '-1' : {'a': 1} |
| + '0' : -1 |
| '1' : 'asd' |
| 'b' : [1, 2, function('strlen')] |
| [0, function('strlen')] |
| [3] |
| ! [1, 2, function('strlen')] |
| ! [1, 2, function('strlen')] |
| ! 1 |
| ! 'asd' |
| ! 2 |
| ! True |
| ! False |
| ! True |
| ! False |
| ! [b'0'] |
| ! {'0': -1} |
| ! (b'', -1) |
| ! None |
| ! [] |
| [0, 1, 2, 3] |
| [0, 1, 2, 3] |
| [0, 1, 3] |
| |
| *** 44,49 **** |
| --- 60,67 ---- |
| ValueError |
| TypeError |
| TypeError |
| + KeyError |
| + KeyError |
| d : locked:0;scope:0 |
| dl : locked:1;scope:0 |
| v: : locked:2;scope:1 |
| |
| *** 376,385 **** |
| window:__dir__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars |
| tabpage:__dir__,number,valid,vars,window,windows |
| range:__dir__,append,end,start |
| ! dictionary:__dir__,keys,locked,scope |
| list:__dir__,extend,locked |
| function:__call__,__dir__,softspace |
| output:__dir__,flush,softspace,write,writelines |
| ' |
| abcdef |
| line : |
| --- 394,406 ---- |
| window:__dir__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars |
| tabpage:__dir__,number,valid,vars,window,windows |
| range:__dir__,append,end,start |
| ! dictionary:__dir__,get,has_key,items,keys,locked,pop,popitem,scope,update,values |
| list:__dir__,extend,locked |
| function:__call__,__dir__,softspace |
| output:__dir__,flush,softspace,write,writelines |
| + {} |
| + {'a': 1} |
| + {'a': 1} |
| ' |
| abcdef |
| line : |
| |
| *** 387,392 **** |
| --- 408,414 ---- |
| abc |
| line : |
| abc' |
| + ['a', 'dup_a'] |
| (<class 'vim.error'>, error('abc',)) |
| (<class 'vim.error'>, error('def',)) |
| (<class 'vim.error'>, error('ghi',)) |
| |
| |
| |
| *** 730,731 **** |
| --- 730,733 ---- |
| { /* Add new patch number below this line */ |
| + /**/ |
| + 1061, |
| /**/ |
| |
| -- |
| How To Keep A Healthy Level Of Insanity: |
| 4. Put your garbage can on your desk and label it "in". |
| |
| /// 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 /// |