0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

updated for version 7.0095

This commit is contained in:
Bram Moolenaar 2005-06-27 22:48:21 +00:00
parent 39a58ca3d4
commit 9a50b1bf21
8 changed files with 2634 additions and 1747 deletions

View File

@ -1,4 +1,4 @@
*spell.txt* For Vim version 7.0aa. Last change: 2005 Jun 25
*spell.txt* For Vim version 7.0aa. Last change: 2005 Jun 27
VIM REFERENCE MANUAL by Bram Moolenaar
@ -266,7 +266,7 @@ find these functions useful:
Vim uses a binary file format for spelling. This greatly speeds up loading
the word list and keeps it small.
*.aff* *.dic* *Myspell*
You can create a Vim spell file from the .aff and .dic files that Myspell
uses. Myspell is used by OpenOffice.org and Mozilla. You should be able to
find them here:
@ -321,9 +321,14 @@ then Vim will try to guess.
When the spell file was written all currently used
spell files will be reloaded.
:mksp[ell] [-ascii] {add-name}
Like ":mkspell" above, using {add-name} as the input
file and producing an output file that has ".spl"
:mksp[ell] [-ascii] {name}.{enc}.add
Like ":mkspell" above, using {name}.{enc}.add as the
input file and producing an output file that has
".spl" appended.
:mksp[ell] [-ascii] {name}
Like ":mkspell" above, using {name} as the input file
and producing an output file that has ".{enc}.spl"
appended.
Since you might want to change a Myspell word list for use with Vim the
@ -557,14 +562,43 @@ contain the table with characters, so that it can be combine with spell files
for any encoding. The .add.spl files also do not contain the table.
MID-WORD CHARACTERS
*spell-midword*
Some characters are only to be considered word characters if they are used in
between two ordinary word characters. An example is the single quote: It is
often used to put text in quotes, thus it can't be recognized as a word
character, but when it appears in between word characters it must be part of
the word. This is needed to detect a spelling error such as they'are. That
should be they're, but since "they" and "are" are words themselves that would
go unnoticed.
These characters are defined with MIDWORD in the .aff file:
MIDWORD '- ~
AFFIXES
*spell-affix-PFX* *spell-affix-SFX*
The usual PFX (prefix) and SFX (suffix) lines are supported (see the Myspell
documentation). Note that Myspell ignores any extra text after the relevant
info. Vim requires this text to start with a "#" so that mistakes don't go
unnoticed. Example:
documentation or the Aspell manual:
http://aspell.net/man-html/Affix-Compression.html).
Note that Myspell ignores any extra text after the relevant info. Vim
requires this text to start with a "#" so that mistakes don't go unnoticed.
Example:
SFX F 0 in [^i]n # Spion > Spionin ~
SFX F 0 nen in # Bauerin > Bauerinnen ~
An extra item for Vim is the "rare" flag. It must come after the other
fields, before a comment. When used then all words that use the affix will be
marked as rare words. Example:
PFX F 0 nene . rare ~
SFX F 0 oin n rare # hardly ever used ~
However, if the word also appears as a good word in another way it won't be
marked as rare.
*spell-affix-PFXPOSTPONE*
When an affix file has very many prefixes that apply to many words it's not
@ -610,8 +644,12 @@ bad words. Example:
BAD ! ~
This can be used to exclude words that would otherwise be good. For example
"the the". Once a word has been marked as bad it won't be undone by
encountering the same word as good.
"the the" in the .dic file:
the the/! ~
Once a word has been marked as bad it won't be undone by encountering the same
word as good.
REPLACEMENTS *spell-affix-REP*

View File

@ -1,4 +1,4 @@
*todo.txt* For Vim version 7.0aa. Last change: 2005 Jun 26
*todo.txt* For Vim version 7.0aa. Last change: 2005 Jun 27
VIM REFERENCE MANUAL by Bram Moolenaar
@ -30,8 +30,7 @@ be worked on, but only if you sponsor Vim development. See |sponsor|.
*known-bugs*
-------------------- Known bugs and current work -----------------------
Is the fix for memory leaks in unreferencing dict/list correct? Is there a
situation where a reference from outside of the structure is not counted?
send fixes for ccmalloc port to FreeBSD.
Add extra list of file locations. Can be used with:
:ltag list of matching tags, like :tselect
@ -101,8 +100,6 @@ PLANNED FOR VERSION 7.0:
- Add SPELLCHECKER, with support for many languages.
- Spell checking code todo's:
- Special handling of ' and -: define in the .aff file.
Aspell does this with "special".
- Support user function to make suggestions:
:set spellsuggest=MySuggest,fast
Also support a list with common mistakes?

View File

@ -198,6 +198,10 @@ struct ufunc
*/
static hashtab_T func_hashtab;
/* list heads for garbage collection */
static dict_T *first_dict = NULL; /* list of all dicts */
static list_T *first_list = NULL; /* list of all lists */
/* From user function to hashitem and back. */
static ufunc_T dumuf;
#define UF2HIKEY(fp) ((fp)->uf_name)
@ -212,7 +216,9 @@ static ufunc_T dumuf;
#define FIXVAR_CNT 12 /* number of fixed variables */
/* structure to hold info for a function that is currently being executed. */
typedef struct funccall_S
typedef struct funccall_S funccall_T;
struct funccall_S
{
ufunc_T *func; /* function being called */
int linenr; /* next line to be executed */
@ -235,7 +241,8 @@ typedef struct funccall_S
#ifdef FEAT_PROFILE
proftime_T prof_child; /* time spent in a child */
#endif
} funccall_T;
funccall_T *caller; /* calling function or NULL */
};
/*
* Info used by a ":for" loop.
@ -382,10 +389,9 @@ static void list_remove __ARGS((list_T *l, listitem_T *item, listitem_T *item2))
static char_u *list2string __ARGS((typval_T *tv));
static int list_join __ARGS((garray_T *gap, list_T *l, char_u *sep, int echo));
static int count_self_ref __ARGS((void *p, int type));
static int count_ref_in_dict __ARGS((dict_T *d, void *rp, int copyID, garray_T *gap));
static int count_ref_in_list __ARGS((list_T *l, void *rp, int copyID, garray_T *gap));
static int count_ref_item __ARGS((typval_T *tv, void *rp, int copyID, garray_T *gap));
static void set_ref_in_ht __ARGS((hashtab_T *ht, int copyID));
static void set_ref_in_list __ARGS((list_T *l, int copyID));
static void set_ref_in_item __ARGS((typval_T *tv, int copyID));
static void dict_unref __ARGS((dict_T *d));
static void dict_free __ARGS((dict_T *d));
@ -460,6 +466,7 @@ static void f_foldtext __ARGS((typval_T *argvars, typval_T *rettv));
static void f_foldtextresult __ARGS((typval_T *argvars, typval_T *rettv));
static void f_foreground __ARGS((typval_T *argvars, typval_T *rettv));
static void f_function __ARGS((typval_T *argvars, typval_T *rettv));
static void f_garbagecollect __ARGS((typval_T *argvars, typval_T *rettv));
static void f_get __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getbufvar __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getchar __ARGS((typval_T *argvars, typval_T *rettv));
@ -749,7 +756,12 @@ eval_clear()
/* global variables */
vars_clear(&globvarht);
/* functions */
free_all_functions();
hash_clear(&func_hashtab);
/* unreferenced lists and dicts */
(void)garbage_collect();
}
#endif
@ -4945,7 +4957,19 @@ failret:
static list_T *
list_alloc()
{
return (list_T *)alloc_clear(sizeof(list_T));
list_T *l;
l = (list_T *)alloc_clear(sizeof(list_T));
if (l != NULL)
{
/* Prepend the list to the list of lists for garbage collection. */
if (first_list != NULL)
first_list->lv_used_prev = l;
l->lv_used_prev = NULL;
l->lv_used_next = first_list;
first_list = l;
}
return l;
}
/*
@ -4956,24 +4980,9 @@ list_alloc()
list_unref(l)
list_T *l;
{
int selfref;
if (l != NULL && l->lv_refcount != DEL_REFCOUNT)
{
if (--l->lv_refcount > 0)
{
/* Check if the dict contains references to itself. These need to
* be subtracted from the reference count to find out if we can
* delete the dict. */
selfref = count_self_ref(l, VAR_LIST);
}
else
selfref = 0;
if (l->lv_refcount - selfref == 0)
/* No references to the list now, free it. */
if (l != NULL && l->lv_refcount != DEL_REFCOUNT && --l->lv_refcount <= 0)
list_free(l);
}
}
/*
* Free a list, including all items it points to.
@ -4988,6 +4997,14 @@ list_free(l)
/* Avoid that recursive reference to the list frees us again. */
l->lv_refcount = DEL_REFCOUNT;
/* Remove the list from the list of lists for garbage collection. */
if (l->lv_used_prev == NULL)
first_list = l->lv_used_next;
else
l->lv_used_prev->lv_used_next = l->lv_used_next;
if (l->lv_used_next != NULL)
l->lv_used_next->lv_used_prev = l->lv_used_prev;
for (item = l->lv_first; item != NULL; item = l->lv_first)
{
/* Remove the item before deleting it. */
@ -5568,157 +5585,168 @@ list_join(gap, l, sep, echo)
}
/*
* Count the number of references for list/dict "p" inside itself.
* This is used to find out if there are no more references elsewhere.
* The tricky bit is that we must not count references in lists/dicts that are
* used elsewhere, but we can only know by counting their references...
* This is a bit slow, but required to avoid leaking memory.
* Garbage collection for lists and dictionaries.
*
* We use reference counts to be able to free most items right away when they
* are no longer used. But for composite items it's possible that it becomes
* unused while the reference count is > 0: When there is a recursive
* reference. Example:
* :let l = [1, 2, 3]
* :let d = {9: l}
* :let l[1] = d
*
* Since this is quite unusual we handle this with garbage collection: every
* once in a while find out which lists and dicts are not referenced from any
* variable.
*
* Here is a good reference text about garbage collection (refers to Python
* but it applies to all reference-counting mechanisms):
* http://python.ca/nas/python/gc/
*/
static int
count_self_ref(p, type)
void *p;
int type;
{
garray_T ga;
typval_T *tv;
int selfref;
int i;
int n;
ga_init2(&ga, sizeof(typval_T *), 10);
if (type == VAR_DICT)
selfref = count_ref_in_dict(p, p, ++current_copyID, &ga);
else
selfref = count_ref_in_list(p, p, ++current_copyID, &ga);
for (i = 0; i < ga.ga_len; ++i)
{
tv = ((typval_T **)ga.ga_data)[i];
if (tv->v_type == VAR_DICT)
{
n = count_ref_in_dict(tv->vval.v_dict, tv->vval.v_dict,
++current_copyID, NULL);
if (n < tv->vval.v_dict->dv_refcount)
{
selfref = 0;
break;
}
}
else
{
n = count_ref_in_list(tv->vval.v_list, tv->vval.v_list,
++current_copyID, NULL);
if (n < tv->vval.v_list->lv_refcount)
{
selfref = 0;
break;
}
}
}
ga_clear(&ga);
return selfref;
}
/*
* Count number of references to "rp" in dictionary "d" and its members.
* We use "copyID" to avoid recursing into the same list/dict twice.
* Do garbage collection for lists and dicts.
* Return TRUE if some memory was freed.
*/
static int
count_ref_in_dict(d, rp, copyID, gap)
dict_T *d;
void *rp;
int copyID;
garray_T *gap;
{
int todo;
hashitem_T *hi;
int n = 0;
todo = d->dv_hashtab.ht_used;
for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
if (!HASHITEM_EMPTY(hi))
{
--todo;
n += count_ref_item(&HI2DI(hi)->di_tv, rp, copyID, gap);
}
return n;
}
/*
* Count number of references to "rp" in list "l" and its members.
* We use "copyID" to avoid recursing into the same list/dict twice.
*/
static int
count_ref_in_list(l, rp, copyID, gap)
list_T *l;
void *rp;
int copyID;
garray_T *gap;
{
listitem_T *li;
int n = 0;
for (li = l->lv_first; li != NULL; li = li->li_next)
n += count_ref_item(&li->li_tv, rp, copyID, gap);
return n;
}
/*
* Count number of references to "rp" in item "tv" and any members.
* We use "copyID" to avoid recursing into the same list/dict twice.
* When "gap" is not NULL store items that require checking for only
* references inside the structure.
*/
static int
count_ref_item(tv, rp, copyID, gap)
typval_T *tv;
void *rp;
int copyID;
garray_T *gap;
int
garbage_collect()
{
dict_T *dd;
list_T *ll;
int copyID = ++current_copyID;
buf_T *buf;
win_T *wp;
int i;
funccall_T *fc;
int did_free = FALSE;
/*
* 1. Go through all accessible variables and mark all lists and dicts
* with copyID.
*/
/* script-local variables */
for (i = 1; i <= ga_scripts.ga_len; ++i)
set_ref_in_ht(&SCRIPT_VARS(i), copyID);
/* buffer-local variables */
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
set_ref_in_ht(&buf->b_vars.dv_hashtab, copyID);
/* window-local variables */
FOR_ALL_WINDOWS(wp)
set_ref_in_ht(&wp->w_vars.dv_hashtab, copyID);
/* global variables */
set_ref_in_ht(&globvarht, copyID);
/* function-local variables */
for (fc = current_funccal; fc != NULL; fc = fc->caller)
{
set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID);
set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID);
}
/*
* 2. Go through the list of dicts and free items without the copyID.
*/
for (dd = first_dict; dd != NULL; )
if (dd->dv_copyID != copyID)
{
dict_free(dd);
did_free = TRUE;
/* restart, next dict may also have been freed */
dd = first_dict;
}
else
dd = dd->dv_used_next;
/*
* 3. Go through the list of lists and free items without the copyID.
*/
for (ll = first_list; ll != NULL; )
if (ll->lv_copyID != copyID)
{
list_free(ll);
did_free = TRUE;
/* restart, next dict may also have been freed */
ll = first_list;
}
else
ll = ll->lv_used_next;
return did_free;
}
/*
* Mark all lists and dicts referenced through hashtab "ht" with "copyID".
*/
static void
set_ref_in_ht(ht, copyID)
hashtab_T *ht;
int copyID;
{
int todo;
hashitem_T *hi;
todo = ht->ht_used;
for (hi = ht->ht_array; todo > 0; ++hi)
if (!HASHITEM_EMPTY(hi))
{
--todo;
set_ref_in_item(&HI2DI(hi)->di_tv, copyID);
}
}
/*
* Mark all lists and dicts referenced through list "l" with "copyID".
*/
static void
set_ref_in_list(l, copyID)
list_T *l;
int copyID;
{
listitem_T *li;
for (li = l->lv_first; li != NULL; li = li->li_next)
set_ref_in_item(&li->li_tv, copyID);
}
/*
* Mark all lists and dicts referenced through typval "tv" with "copyID".
*/
static void
set_ref_in_item(tv, copyID)
typval_T *tv;
int copyID;
{
dict_T *dd;
list_T *ll;
int n;
switch (tv->v_type)
{
case VAR_DICT:
dd = tv->vval.v_dict;
if (dd == rp)
return 1; /* match, count it */
if (dd->dv_copyID == copyID)
return 0; /* already inspected this dict */
dd->dv_copyID = copyID;
n = count_ref_in_dict(dd, rp, copyID, gap);
if (n > 0 && gap != NULL && dd->dv_refcount > 1)
if (dd->dv_copyID != copyID)
{
/* We must later check that the references to this dict are
* all in the structure we are freeing. */
if (ga_grow(gap, 1) == FAIL)
return 0;
((typval_T **)gap->ga_data)[gap->ga_len++] = tv;
/* Didn't see this dict yet. */
dd->dv_copyID = copyID;
set_ref_in_ht(&dd->dv_hashtab, copyID);
}
return n;
break;
case VAR_LIST:
ll = tv->vval.v_list;
if (ll == rp)
return 1; /* match, count it */
if (ll->lv_copyID == copyID)
return 0; /* already inspected this list */
ll->lv_copyID = copyID;
n = count_ref_in_list(ll, rp, copyID, gap);
if (n > 0 && gap != NULL && ll->lv_refcount > 1)
if (ll->lv_copyID != copyID)
{
/* We must later check that the references to this list are
* all in the structure we are freeing. */
if (ga_grow(gap, 1) == FAIL)
return 0;
((typval_T **)gap->ga_data)[gap->ga_len++] = tv;
/* Didn't see this list yet. */
ll->lv_copyID = copyID;
set_ref_in_list(ll, copyID);
}
return n;
break;
}
return 0;
return;
}
/*
@ -5732,6 +5760,12 @@ dict_alloc()
d = (dict_T *)alloc(sizeof(dict_T));
if (d != NULL)
{
/* Add the list to the hashtable for garbage collection. */
if (first_dict != NULL)
first_dict->dv_used_prev = d;
d->dv_used_next = first_dict;
d->dv_used_prev = NULL;
hash_init(&d->dv_hashtab);
d->dv_lock = 0;
d->dv_refcount = 0;
@ -5748,24 +5782,9 @@ dict_alloc()
dict_unref(d)
dict_T *d;
{
int selfref;
if (d != NULL && d->dv_refcount != DEL_REFCOUNT)
{
if (--d->dv_refcount > 0)
{
/* Check if the dict contains references to itself. These need to
* be subtracted from the reference count to find out if we can
* delete the dict. */
selfref = count_self_ref(d, VAR_DICT);
}
else
selfref = 0;
if (d->dv_refcount - selfref == 0)
/* No references to the dict now, free it. */
if (d != NULL && d->dv_refcount != DEL_REFCOUNT && --d->dv_refcount <= 0)
dict_free(d);
}
}
/*
* Free a Dictionary, including all items it contains.
@ -5782,8 +5801,15 @@ dict_free(d)
/* Avoid that recursive reference to the dict frees us again. */
d->dv_refcount = DEL_REFCOUNT;
/* Lock the hashtab, we don't want it to resize while looping through it.
* */
/* Remove the dict from the list of dicts for garbage collection. */
if (d->dv_used_prev == NULL)
first_dict = d->dv_used_next;
else
d->dv_used_prev->dv_used_next = d->dv_used_next;
if (d->dv_used_next != NULL)
d->dv_used_next->dv_used_prev = d->dv_used_prev;
/* Lock the hashtab, we don't want it to resize while freeing items. */
hash_lock(&d->dv_hashtab);
todo = d->dv_hashtab.ht_used;
for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
@ -6505,6 +6531,7 @@ static struct fst
{"foldtextresult", 1, 1, f_foldtextresult},
{"foreground", 0, 0, f_foreground},
{"function", 1, 1, f_function},
{"garbagecollect", 0, 0, f_garbagecollect},
{"get", 2, 3, f_get},
{"getbufvar", 2, 2, f_getbufvar},
{"getchar", 0, 1, f_getchar},
@ -8885,6 +8912,18 @@ f_function(argvars, rettv)
}
}
/*
* "garbagecollect()" function
*/
/*ARGSUSED*/
static void
f_garbagecollect(argvars, rettv)
typval_T *argvars;
typval_T *rettv;
{
garbage_collect();
}
/*
* "get()" function
*/
@ -15506,8 +15545,10 @@ find_var_in_ht(ht, varname, writing)
case 'v': return &vimvars_var;
case 'b': return &curbuf->b_bufvar;
case 'w': return &curwin->w_winvar;
case 'l': return &current_funccal->l_vars_var;
case 'a': return &current_funccal->l_avars_var;
case 'l': return current_funccal == NULL
? NULL : &current_funccal->l_vars_var;
case 'a': return current_funccal == NULL
? NULL : &current_funccal->l_avars_var;
}
return NULL;
}
@ -15689,6 +15730,7 @@ vars_clear_ext(ht, free_val)
}
}
hash_clear(ht);
ht->ht_used = 0;
}
/*
@ -15789,7 +15831,7 @@ set_var(name, tv, copy)
}
if (function_exists(name))
{
EMSG2(_("705: Variable name conflicts with existing function: %s"),
EMSG2(_("E705: Variable name conflicts with existing function: %s"),
name);
return;
}
@ -17569,7 +17611,6 @@ call_user_func(fp, argcount, argvars, rettv, firstline, lastline, selfdict)
linenr_T save_sourcing_lnum;
scid_T save_current_SID;
funccall_T fc;
funccall_T *save_fcp = current_funccal;
int save_did_emsg;
static int depth = 0;
dictitem_T *v;
@ -17594,6 +17635,7 @@ call_user_func(fp, argcount, argvars, rettv, firstline, lastline, selfdict)
line_breakcheck(); /* check for CTRL-C hit */
fc.caller = current_funccal;
current_funccal = &fc;
fc.func = fp;
fc.rettv = rettv;
@ -17752,7 +17794,7 @@ call_user_func(fp, argcount, argvars, rettv, firstline, lastline, selfdict)
if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL))
func_do_profile(fp);
if (fp->uf_profiling
|| (save_fcp != NULL && &save_fcp->func->uf_profiling))
|| (fc.caller != NULL && &fc.caller->func->uf_profiling))
{
++fp->uf_tm_count;
profile_start(&fp->uf_tm_start);
@ -17782,17 +17824,17 @@ call_user_func(fp, argcount, argvars, rettv, firstline, lastline, selfdict)
}
#ifdef FEAT_PROFILE
if (fp->uf_profiling || (save_fcp != NULL && &save_fcp->func->uf_profiling))
if (fp->uf_profiling || (fc.caller != NULL && &fc.caller->func->uf_profiling))
{
profile_end(&fp->uf_tm_start);
profile_sub_wait(&wait_start, &fp->uf_tm_start);
profile_add(&fp->uf_tm_total, &fp->uf_tm_start);
profile_add(&fp->uf_tm_self, &fp->uf_tm_start);
profile_sub(&fp->uf_tm_self, &fp->uf_tm_children);
if (save_fcp != NULL && &save_fcp->func->uf_profiling)
if (fc.caller != NULL && &fc.caller->func->uf_profiling)
{
profile_add(&save_fcp->func->uf_tm_children, &fp->uf_tm_start);
profile_add(&save_fcp->func->uf_tml_children, &fp->uf_tm_start);
profile_add(&fc.caller->func->uf_tm_children, &fp->uf_tm_start);
profile_add(&fc.caller->func->uf_tml_children, &fp->uf_tm_start);
}
}
#endif
@ -17850,7 +17892,7 @@ call_user_func(fp, argcount, argvars, rettv, firstline, lastline, selfdict)
}
did_emsg |= save_did_emsg;
current_funccal = save_fcp;
current_funccal = fc.caller;
/* The a: variables typevals were not alloced, only free the allocated
* variables. */

View File

@ -3199,6 +3199,9 @@ do_ecmd(fnum, ffname, sfname, eap, newlnum, flags)
#ifdef FEAT_DIFF
curwin->w_p_diff = FALSE; /* No 'diff' */
#endif
#ifdef FEAT_SYN_HL
curwin->w_p_spell = FALSE; /* No spell checking */
#endif
#ifdef FEAT_AUTOCMD
buf = curbuf;

View File

@ -250,7 +250,7 @@ hash_set(hi, key)
/*
* Remove item "hi" from hashtable "ht". "hi" must have been obtained with
* hash_lookup() and point to an empty item.
* hash_lookup().
* The caller must take care of freeing the item itself.
*/
void

View File

@ -148,7 +148,7 @@ mch_inchar(buf, maxlen, time, tb_change_cnt)
return 3;
}
#endif
updatescript(0);
before_blocking();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@ void hash_debug_results __ARGS((void));
int hash_add __ARGS((hashtab_T *ht, char_u *key));
int hash_add_item __ARGS((hashtab_T *ht, hashitem_T *hi, char_u *key, hash_T hash));
void hash_remove __ARGS((hashtab_T *ht, hashitem_T *hi));
int hash_delete __ARGS((hashtab_T *ht, char_u *key));
void hash_lock __ARGS((hashtab_T *ht));
void hash_unlock __ARGS((hashtab_T *ht));
hash_T hash_hash __ARGS((char_u *key));