forked from bartvdbraak/blender
Added UI for suggestions list. Works with arrow-keys and mouse wheel, accept with Enter, reject with Esc or click elsewhere. Mouse selection not yet supported. The script is called from the File->Text Plugins menu.
Tidied python script, the C suggestions functions and fixed some bugs including suggestions not being freed properly.
This commit is contained in:
parent
bdc030c664
commit
e68834c75b
@ -6,12 +6,11 @@ Group: 'TextPlugin'
|
||||
Tooltip: 'Suggests completions for the word at the cursor in a python script'
|
||||
"""
|
||||
|
||||
import bpy
|
||||
import bpy, __builtin__, token
|
||||
from Blender import Text
|
||||
from StringIO import StringIO
|
||||
from inspect import *
|
||||
from tokenize import generate_tokens
|
||||
import token
|
||||
|
||||
TK_TYPE = 0
|
||||
TK_TOKEN = 1
|
||||
@ -21,32 +20,48 @@ TK_LINE = 4
|
||||
TK_ROW = 0
|
||||
TK_COL = 1
|
||||
|
||||
execs = [] # Used to establish the same import context across defs
|
||||
|
||||
keywords = ['and', 'del', 'from', 'not', 'while', 'as', 'elif', 'global',
|
||||
'or', 'with', 'assert', 'else', 'if', 'pass', 'yield',
|
||||
'break', 'except', 'import', 'print', 'class', 'exec', 'in',
|
||||
'raise', 'continue', 'finally', 'is', 'return', 'def', 'for',
|
||||
'lambda', 'try' ]
|
||||
|
||||
execs = [] # Used to establish the same import context across defs (import is scope sensitive)
|
||||
|
||||
def getBuiltins():
|
||||
builtins = []
|
||||
bi = dir(__builtin__)
|
||||
for k in bi:
|
||||
v = eval(k)
|
||||
if ismodule(v): t='m'
|
||||
elif callable(v): t='f'
|
||||
else: t='v'
|
||||
builtins.append((k, t))
|
||||
return builtins
|
||||
|
||||
|
||||
def getKeywords():
|
||||
global keywords
|
||||
return [(k, 'k') for k in keywords]
|
||||
|
||||
|
||||
def getTokens(txt):
|
||||
global tokens_cached
|
||||
if tokens_cached==None:
|
||||
lines = txt.asLines()
|
||||
str = '\n'.join(lines)
|
||||
readline = StringIO(str).readline
|
||||
g = generate_tokens(readline)
|
||||
tokens = []
|
||||
for t in g: tokens.append(t)
|
||||
tokens_cached = tokens
|
||||
return tokens_cached
|
||||
tokens_cached = None
|
||||
lines = txt.asLines()
|
||||
str = '\n'.join(lines)
|
||||
readline = StringIO(str).readline
|
||||
g = generate_tokens(readline)
|
||||
tokens = []
|
||||
for t in g: tokens.append(t)
|
||||
return tokens
|
||||
|
||||
|
||||
def isNameChar(s):
|
||||
return s.isalnum() or s in ['_']
|
||||
return (s.isalnum() or s == '_')
|
||||
|
||||
# Returns words preceding the cursor that are separated by periods as a list in the
|
||||
# same order
|
||||
|
||||
# Returns words preceding the cursor that are separated by periods as a list in
|
||||
# the same order
|
||||
def getCompletionSymbols(txt):
|
||||
(l, c)= txt.getCursorPos()
|
||||
lines = txt.asLines()
|
||||
@ -68,7 +83,14 @@ def getCompletionSymbols(txt):
|
||||
def getGlobals(txt):
|
||||
global execs
|
||||
|
||||
tokens = getTokens(txt)
|
||||
# Unfortunately, tokenize may fail if the script leaves brackets or strings
|
||||
# open. For now we return an empty list, leaving builtins and keywords as
|
||||
# the only globals. (on the TODO list)
|
||||
try:
|
||||
tokens = getTokens(txt)
|
||||
except:
|
||||
return []
|
||||
|
||||
globals = dict()
|
||||
for i in range(len(tokens)):
|
||||
|
||||
@ -92,6 +114,7 @@ def getGlobals(txt):
|
||||
x = tokens[i][TK_LINE].strip()
|
||||
k = tokens[i][TK_TOKEN]
|
||||
execs.append(x)
|
||||
exec 'try: '+x+'\nexcept: pass'
|
||||
|
||||
# Add the symbol name to the return list
|
||||
globals[k] = 'm'
|
||||
@ -105,16 +128,17 @@ def getGlobals(txt):
|
||||
# Add the import to the execs list
|
||||
x = tokens[i][TK_LINE].strip()
|
||||
execs.append(x)
|
||||
exec 'try: '+x+'\nexcept: pass'
|
||||
|
||||
# Import parent module so we can process it for sub modules
|
||||
parent = ''.join([t[TK_TOKEN] for t in tokens[fr+1:i-1]])
|
||||
exec "import "+parent
|
||||
exec 'try: import '+parent+'\nexcept: pass'
|
||||
|
||||
# All submodules, functions, etc.
|
||||
if tokens[i][TK_TOKEN]=='*':
|
||||
|
||||
# Add each symbol name to the return list
|
||||
exec "d="+parent+".__dict__.items()"
|
||||
d = eval(parent).__dict__.items()
|
||||
for k,v in d:
|
||||
if not globals.has_key(k) or not globals[k]:
|
||||
t='v'
|
||||
@ -130,7 +154,7 @@ def getGlobals(txt):
|
||||
if not globals.has_key(k) or not globals[k]:
|
||||
t='v'
|
||||
try:
|
||||
exec 'v='+parent+'.'+k
|
||||
v = eval(parent+'.'+k)
|
||||
if ismodule(v): t='m'
|
||||
elif callable(v): t='f'
|
||||
except: pass
|
||||
@ -149,35 +173,13 @@ def getGlobals(txt):
|
||||
t='v'
|
||||
globals[k] = t
|
||||
|
||||
return globals
|
||||
return globals.items()
|
||||
|
||||
def cmpi0(x, y):
|
||||
return cmp(x[0].lower(), y[0].lower())
|
||||
|
||||
def globalSuggest(txt, cs):
|
||||
global execs
|
||||
|
||||
suggestions = dict()
|
||||
(row, col) = txt.getCursorPos()
|
||||
globals = getGlobals(txt)
|
||||
|
||||
# Sometimes we have conditional includes which will fail if the module
|
||||
# cannot be found. So we protect outselves in a try block
|
||||
for x in execs:
|
||||
exec 'try: '+x+'\nexcept: pass'
|
||||
|
||||
if len(cs)==0:
|
||||
sub = ''
|
||||
else:
|
||||
sub = cs[0].lower()
|
||||
print 'Search:', sub
|
||||
|
||||
for k,t in globals.items():
|
||||
if k.lower().startswith(sub):
|
||||
suggestions[k] = t
|
||||
|
||||
l = list(suggestions.items())
|
||||
return sorted (l, cmp=cmpi0)
|
||||
return globals
|
||||
|
||||
|
||||
# Only works for 'static' members (eg. Text.Get)
|
||||
def memberSuggest(txt, cs):
|
||||
@ -194,28 +196,28 @@ def memberSuggest(txt, cs):
|
||||
suggestions = dict()
|
||||
(row, col) = txt.getCursorPos()
|
||||
|
||||
sub = cs[len(cs)-1].lower()
|
||||
print 'Search:', sub
|
||||
sub = cs[len(cs)-1]
|
||||
|
||||
t=None
|
||||
m=None
|
||||
pre='.'.join(cs[:-1])
|
||||
try:
|
||||
exec "t="+pre
|
||||
m = eval(pre)
|
||||
except:
|
||||
print 'Failed to assign '+pre
|
||||
print execs
|
||||
print cs
|
||||
print pre+ ' not found or not imported.'
|
||||
|
||||
if t!=None:
|
||||
for k,v in t.__dict__.items():
|
||||
if m!=None:
|
||||
for k,v in m.__dict__.items():
|
||||
if ismodule(v): t='m'
|
||||
elif callable(v): t='f'
|
||||
else: t='v'
|
||||
if k.lower().startswith(sub):
|
||||
suggestions[k] = t
|
||||
suggestions[k] = t
|
||||
|
||||
l = list(suggestions.items())
|
||||
return sorted (l, cmp=cmpi0)
|
||||
return suggestions.items()
|
||||
|
||||
|
||||
def cmp0(x, y):
|
||||
return cmp(x[0], y[0])
|
||||
|
||||
|
||||
def main():
|
||||
txt = bpy.data.texts.active
|
||||
@ -225,10 +227,12 @@ def main():
|
||||
|
||||
if len(cs)<=1:
|
||||
l = globalSuggest(txt, cs)
|
||||
txt.suggest(l, cs[len(cs)-1])
|
||||
|
||||
l.extend(getBuiltins())
|
||||
l.extend(getKeywords())
|
||||
else:
|
||||
l = memberSuggest(txt, cs)
|
||||
txt.suggest(l, cs[len(cs)-1])
|
||||
|
||||
l.sort(cmp=cmp0)
|
||||
txt.suggest(l, cs[len(cs)-1])
|
||||
|
||||
main()
|
||||
|
@ -57,18 +57,22 @@ typedef struct SuggItem {
|
||||
typedef struct SuggList {
|
||||
SuggItem *first, *last;
|
||||
SuggItem *firstmatch, *lastmatch;
|
||||
SuggItem *selected;
|
||||
} SuggList;
|
||||
|
||||
void free_suggestions();
|
||||
|
||||
void add_suggestion(const char *name, char type);
|
||||
void update_suggestions(const char *prefix);
|
||||
void suggest_add(const char *name, char type);
|
||||
void suggest_prefix(const char *prefix);
|
||||
SuggItem *suggest_first();
|
||||
SuggItem *suggest_last();
|
||||
|
||||
void set_suggest_text(Text *text);
|
||||
void clear_suggest_text();
|
||||
short is_suggest_active(Text *text);
|
||||
void suggest_set_text(Text *text);
|
||||
void suggest_clear_text();
|
||||
short suggest_is_active(Text *text);
|
||||
|
||||
void suggest_set_selected(SuggItem *sel);
|
||||
SuggItem *suggest_get_selected();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -40,14 +40,17 @@ static SuggList suggestions= {NULL, NULL, NULL, NULL};
|
||||
static Text *suggText = NULL;
|
||||
|
||||
void free_suggestions() {
|
||||
SuggItem *item;
|
||||
for (item = suggestions.last; item; item=item->prev)
|
||||
SuggItem *item, *prev;
|
||||
for (item = suggestions.last; item; item=prev) {
|
||||
prev = item->prev;
|
||||
MEM_freeN(item);
|
||||
}
|
||||
suggestions.first = suggestions.last = NULL;
|
||||
suggestions.firstmatch = suggestions.lastmatch = NULL;
|
||||
suggestions.selected = NULL;
|
||||
}
|
||||
|
||||
void add_suggestion(const char *name, char type) {
|
||||
void suggest_add(const char *name, char type) {
|
||||
SuggItem *newitem;
|
||||
|
||||
newitem = MEM_mallocN(sizeof(SuggItem) + strlen(name) + 1, "SuggestionItem");
|
||||
@ -63,6 +66,7 @@ void add_suggestion(const char *name, char type) {
|
||||
|
||||
if (!suggestions.first) {
|
||||
suggestions.first = suggestions.last = newitem;
|
||||
suggestions.selected = newitem;
|
||||
} else {
|
||||
newitem->prev = suggestions.last;
|
||||
suggestions.last->next = newitem;
|
||||
@ -70,13 +74,13 @@ void add_suggestion(const char *name, char type) {
|
||||
}
|
||||
}
|
||||
|
||||
void update_suggestions(const char *prefix) {
|
||||
void suggest_prefix(const char *prefix) {
|
||||
SuggItem *match, *first, *last;
|
||||
int cmp, len = strlen(prefix);
|
||||
|
||||
if (!suggestions.first) return;
|
||||
if (len==0) {
|
||||
suggestions.firstmatch = suggestions.first;
|
||||
suggestions.selected = suggestions.firstmatch = suggestions.first;
|
||||
suggestions.lastmatch = suggestions.last;
|
||||
return;
|
||||
}
|
||||
@ -96,10 +100,10 @@ void update_suggestions(const char *prefix) {
|
||||
}
|
||||
if (first) {
|
||||
if (!last) last = suggestions.last;
|
||||
suggestions.firstmatch = first;
|
||||
suggestions.selected = suggestions.firstmatch = first;
|
||||
suggestions.lastmatch = last;
|
||||
} else {
|
||||
suggestions.firstmatch = suggestions.lastmatch = NULL;
|
||||
suggestions.selected = suggestions.firstmatch = suggestions.lastmatch = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,15 +115,23 @@ SuggItem *suggest_last() {
|
||||
return suggestions.lastmatch;
|
||||
}
|
||||
|
||||
void set_suggest_text(Text *text) {
|
||||
void suggest_set_text(Text *text) {
|
||||
suggText = text;
|
||||
}
|
||||
|
||||
void clear_suggest_text() {
|
||||
void suggest_clear_text() {
|
||||
free_suggestions();
|
||||
suggText = NULL;
|
||||
}
|
||||
|
||||
short is_suggest_active(Text *text) {
|
||||
short suggest_is_active(Text *text) {
|
||||
return suggText==text ? 1 : 0;
|
||||
}
|
||||
|
||||
void suggest_set_selected(SuggItem *sel) {
|
||||
suggestions.selected = sel;
|
||||
}
|
||||
|
||||
SuggItem *suggest_get_selected() {
|
||||
return suggestions.selected;
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ static PyMethodDef BPy_Text_methods[] = {
|
||||
{"setCursorPos", ( PyCFunction ) Text_setCursorPos, METH_VARARGS,
|
||||
"(row, col) - Set the cursor position to (row, col)"},
|
||||
{"suggest", ( PyCFunction ) Text_suggest, METH_VARARGS,
|
||||
"(list) - List of tuples of the form (name, type) where type is one of 'm', 'v', 'f' for module, variable and function respectively"},
|
||||
"(list) - List of tuples of the form (name, type) where type is one of 'm', 'v', 'f', 'k' for module, variable, function and keyword respectively"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
@ -544,7 +544,7 @@ static PyObject *Text_suggest( BPy_Text * self, PyObject * args )
|
||||
"Active text area has no Text object");
|
||||
|
||||
list_len = PyList_Size(list);
|
||||
clear_suggest_text();
|
||||
suggest_clear_text();
|
||||
|
||||
for (i = 0; i < list_len; i++) {
|
||||
item = PyList_GetItem(list, i);
|
||||
@ -555,14 +555,14 @@ static PyObject *Text_suggest( BPy_Text * self, PyObject * args )
|
||||
name = PyString_AsString(PyTuple_GetItem(item, 0));
|
||||
type = PyString_AsString(PyTuple_GetItem(item, 1))[0];
|
||||
|
||||
if (!strlen(name) || (type!='m' && type!='v' && type!='f'))
|
||||
if (!strlen(name) || (type!='m' && type!='v' && type!='f' && type!='k'))
|
||||
return EXPP_ReturnPyObjError(PyExc_AttributeError,
|
||||
"layer values must be in the range [1, 20]" );
|
||||
"names must be non-empty and types in ['m', 'v', 'f', 'k']" );
|
||||
|
||||
add_suggestion(name, type);
|
||||
suggest_add(name, type);
|
||||
}
|
||||
update_suggestions(prefix);
|
||||
set_suggest_text(st->text);
|
||||
suggest_prefix(prefix);
|
||||
suggest_set_text(st->text);
|
||||
scrarea_queue_redraw(curarea);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
|
@ -99,6 +99,10 @@ static int check_delim(char *string);
|
||||
static int check_numbers(char *string);
|
||||
static int check_builtinfuncs(char *string);
|
||||
static int check_specialvars(char *string);
|
||||
static int check_identifier(char ch);
|
||||
|
||||
static void get_suggest_prefix(Text *text);
|
||||
static void confirm_suggestion(Text *text);
|
||||
|
||||
static void *last_txt_find_string= NULL;
|
||||
|
||||
@ -1000,16 +1004,63 @@ static void do_selection(SpaceText *st, int selecting)
|
||||
txt_undo_add_toop(st->text, UNDO_STO, sell, selc, linep2, charp2);
|
||||
}
|
||||
|
||||
void draw_suggestion_list(SpaceText *st) {
|
||||
SuggItem *item, *last;
|
||||
|
||||
if (!is_suggest_active(st->text)) return;
|
||||
#define SUGG_LIST_SIZE 7
|
||||
#define SUGG_LIST_WIDTH 20
|
||||
|
||||
for (item=suggest_first(), last=suggest_last(); item; item=item->next) {
|
||||
/* Useful for testing but soon to be replaced by UI list */
|
||||
printf("Suggest: %c %s\n", item->type, item->name);
|
||||
if (item == last)
|
||||
break;
|
||||
void draw_suggestion_list(SpaceText *st) {
|
||||
SuggItem *item, *first, *last, *sel;
|
||||
TextLine *tmp;
|
||||
char str[SUGG_LIST_WIDTH+1];
|
||||
int w, boxw=0, boxh, i, l, x, y, b;
|
||||
|
||||
if (!st || !st->text) return;
|
||||
if (!suggest_is_active(st->text)) return;
|
||||
|
||||
first = suggest_first();
|
||||
last = suggest_last();
|
||||
sel = suggest_get_selected();
|
||||
//if (!first || !last || !sel) return;
|
||||
|
||||
for (tmp=st->text->curl, l=-st->top; tmp; tmp=tmp->prev, l++);
|
||||
boxw = SUGG_LIST_WIDTH*spacetext_get_fontwidth(st) + 20;
|
||||
boxh = SUGG_LIST_SIZE*st->lheight + 8;
|
||||
x = spacetext_get_fontwidth(st)*st->text->curc + 50; // TODO: Replace + 50
|
||||
y = curarea->winy - st->lheight*l - 2;
|
||||
|
||||
BIF_ThemeColor(TH_SHADE1);
|
||||
glRecti(x-1, y+1, x+boxw+1, y-boxh-1);
|
||||
BIF_ThemeColor(TH_BACK);
|
||||
glRecti(x, y, x+boxw, y-boxh);
|
||||
|
||||
for (i=0, item=sel; i<3 && item && item!=first; i++, item=item->prev);
|
||||
|
||||
for (i=0; i<SUGG_LIST_SIZE && item; i++, item=item->next) {
|
||||
|
||||
y -= st->lheight;
|
||||
|
||||
strncpy(str, item->name, SUGG_LIST_WIDTH);
|
||||
str[SUGG_LIST_WIDTH] = '\0';
|
||||
|
||||
w = BMF_GetStringWidth(spacetext_get_font(st), str);
|
||||
|
||||
if (item == sel) {
|
||||
BIF_ThemeColor(TH_SHADE2);
|
||||
glRecti(x+16, y-3, x+16+w, y+st->lheight-3);
|
||||
}
|
||||
b=1; /* b=1 colour block, text is default. b=0 no block, colour text */
|
||||
switch (item->type) {
|
||||
case 'k': BIF_ThemeColor(TH_SYNTAX_B); b=0; break;
|
||||
case 'm': BIF_ThemeColor(TH_TEXT); break;
|
||||
case 'f': BIF_ThemeColor(TH_SYNTAX_L); break;
|
||||
case 'v': BIF_ThemeColor(TH_SYNTAX_N); break;
|
||||
}
|
||||
if (b) {
|
||||
glRecti(x+8, y+2, x+11, y+5);
|
||||
BIF_ThemeColor(TH_TEXT);
|
||||
}
|
||||
text_draw(st, str, 0, 0, 1, x+16, y-1, NULL);
|
||||
|
||||
if (item == last) break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1484,6 +1535,48 @@ static void set_tabs(Text *text)
|
||||
st->currtab_set = setcurr_tab(text);
|
||||
}
|
||||
|
||||
static void get_suggest_prefix(Text *text) {
|
||||
int i, len;
|
||||
char *line, tmp[256];
|
||||
|
||||
if (!text) return;
|
||||
if (!suggest_is_active(text)) return;
|
||||
|
||||
line= text->curl->line;
|
||||
for (i=text->curc-1; i>=0; i--)
|
||||
if (!check_identifier(line[i]))
|
||||
break;
|
||||
i++;
|
||||
len= text->curc-i;
|
||||
if (len > 255) {
|
||||
printf("Suggestion prefix too long\n");
|
||||
return;
|
||||
}
|
||||
strncpy(tmp, line+i, len);
|
||||
tmp[len]= '\0';
|
||||
suggest_prefix(tmp);
|
||||
}
|
||||
|
||||
static void confirm_suggestion(Text *text) {
|
||||
int i, len;
|
||||
char *line;
|
||||
SuggItem *sel;
|
||||
|
||||
if (!text) return;
|
||||
if (!suggest_is_active(text)) return;
|
||||
|
||||
sel = suggest_get_selected();
|
||||
if (!sel) return;
|
||||
|
||||
line= text->curl->line;
|
||||
for (i=text->curc-1; i>=0; i--)
|
||||
if (!check_identifier(line[i]))
|
||||
break;
|
||||
i++;
|
||||
len= text->curc-i;
|
||||
txt_insert_buf(text, sel->name+len);
|
||||
}
|
||||
|
||||
void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
{
|
||||
unsigned short event= evt->event;
|
||||
@ -1492,6 +1585,7 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
SpaceText *st= curarea->spacedata.first;
|
||||
Text *text;
|
||||
int do_draw=0, p;
|
||||
int suggesting=0, do_suggest=0; /* 0:just redraw, -1:clear, 1:update prefix */
|
||||
|
||||
if (st==NULL || st->spacetype != SPACE_TEXT) return;
|
||||
|
||||
@ -1554,6 +1648,8 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
suggesting = suggest_is_active(text);
|
||||
|
||||
if (event==LEFTMOUSE) {
|
||||
if (val) {
|
||||
@ -1573,6 +1669,7 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
}
|
||||
do_draw= 1;
|
||||
}
|
||||
do_suggest= -1;
|
||||
}
|
||||
} else if (event==MIDDLEMOUSE) {
|
||||
if (val) {
|
||||
@ -1586,6 +1683,7 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
{
|
||||
do_textscroll(st, 1);
|
||||
}
|
||||
do_suggest= -1;
|
||||
}
|
||||
} else if (event==RIGHTMOUSE) {
|
||||
if (val) {
|
||||
@ -1618,6 +1716,7 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
do_suggest= -1;
|
||||
}
|
||||
} else if (ascii) {
|
||||
if (text && text->id.lib) {
|
||||
@ -1627,8 +1726,10 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
if (st->showsyntax) get_format_string(st);
|
||||
pop_space_text(st);
|
||||
do_draw= 1;
|
||||
do_suggest= 1;
|
||||
}
|
||||
} else if (val) {
|
||||
do_suggest= -1;
|
||||
switch (event) {
|
||||
case AKEY:
|
||||
if (G.qual & LR_ALTKEY) {
|
||||
@ -1891,6 +1992,9 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
do_draw= 1;
|
||||
}
|
||||
break;
|
||||
case ESCKEY:
|
||||
do_suggest= -1;
|
||||
break;
|
||||
case TABKEY:
|
||||
if (text && text->id.lib) {
|
||||
error_libdata();
|
||||
@ -1920,6 +2024,11 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
error_libdata();
|
||||
break;
|
||||
}
|
||||
if (suggesting) {
|
||||
confirm_suggestion(text);
|
||||
if (st->showsyntax) get_format_string(st);
|
||||
break;
|
||||
}
|
||||
//double check tabs before splitting the line
|
||||
st->currtab_set = setcurr_tab(text);
|
||||
txt_split_curline(text);
|
||||
@ -1951,6 +2060,7 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
if (st->showsyntax) get_format_string(st);
|
||||
do_draw= 1;
|
||||
pop_space_text(st);
|
||||
do_suggest= 1;
|
||||
break;
|
||||
case DELKEY:
|
||||
if (text && text->id.lib) {
|
||||
@ -1970,8 +2080,16 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
case INSERTKEY:
|
||||
st->overwrite= !st->overwrite;
|
||||
do_draw= 1;
|
||||
do_suggest= 0;
|
||||
break;
|
||||
case DOWNARROWKEY:
|
||||
if (suggesting) {
|
||||
SuggItem *sel = suggest_get_selected();
|
||||
if (sel && sel!=suggest_last() && sel->next)
|
||||
suggest_set_selected(sel->next);
|
||||
do_suggest= 0;
|
||||
break;
|
||||
}
|
||||
txt_move_down(text, G.qual & LR_SHIFTKEY);
|
||||
set_tabs(text);
|
||||
do_draw= 1;
|
||||
@ -2000,17 +2118,42 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
pop_space_text(st);
|
||||
break;
|
||||
case UPARROWKEY:
|
||||
if (suggesting) {
|
||||
SuggItem *sel = suggest_get_selected();
|
||||
if (sel && sel!=suggest_first() && sel->prev)
|
||||
suggest_set_selected(sel->prev);
|
||||
do_suggest= 0;
|
||||
break;
|
||||
}
|
||||
txt_move_up(text, G.qual & LR_SHIFTKEY);
|
||||
set_tabs(text);
|
||||
do_draw= 1;
|
||||
pop_space_text(st);
|
||||
break;
|
||||
case PAGEDOWNKEY:
|
||||
screen_skip(st, st->viewlines);
|
||||
if (suggesting) {
|
||||
int i;
|
||||
SuggItem *sel = suggest_get_selected();
|
||||
for (i=0; i<SUGG_LIST_SIZE-1 && sel && sel!=suggest_last() && sel->next; i++, sel=sel->next)
|
||||
suggest_set_selected(sel->next);
|
||||
do_suggest= 0;
|
||||
break;
|
||||
} else {
|
||||
screen_skip(st, st->viewlines);
|
||||
}
|
||||
do_draw= 1;
|
||||
break;
|
||||
case PAGEUPKEY:
|
||||
screen_skip(st, -st->viewlines);
|
||||
if (suggesting) {
|
||||
int i;
|
||||
SuggItem *sel = suggest_get_selected();
|
||||
for (i=0; i<SUGG_LIST_SIZE-1 && sel && sel!=suggest_first() && sel->prev; i++, sel=sel->prev)
|
||||
suggest_set_selected(sel->prev);
|
||||
do_suggest= 0;
|
||||
break;
|
||||
} else {
|
||||
screen_skip(st, -st->viewlines);
|
||||
}
|
||||
do_draw= 1;
|
||||
break;
|
||||
case HOMEKEY:
|
||||
@ -2024,16 +2167,41 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
pop_space_text(st);
|
||||
break;
|
||||
case WHEELUPMOUSE:
|
||||
screen_skip(st, -U.wheellinescroll);
|
||||
if (suggesting) {
|
||||
SuggItem *sel = suggest_get_selected();
|
||||
if (sel && sel!=suggest_first() && sel->prev)
|
||||
suggest_set_selected(sel->prev);
|
||||
do_suggest= 0;
|
||||
} else {
|
||||
screen_skip(st, -U.wheellinescroll);
|
||||
}
|
||||
do_draw= 1;
|
||||
break;
|
||||
case WHEELDOWNMOUSE:
|
||||
screen_skip(st, U.wheellinescroll);
|
||||
if (suggesting) {
|
||||
SuggItem *sel = suggest_get_selected();
|
||||
if (sel && sel!=suggest_last() && sel->next)
|
||||
suggest_set_selected(sel->next);
|
||||
do_suggest= 0;
|
||||
} else {
|
||||
screen_skip(st, U.wheellinescroll);
|
||||
}
|
||||
do_draw= 1;
|
||||
break;
|
||||
default:
|
||||
do_suggest= 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (suggesting) {
|
||||
if (do_suggest == -1) {
|
||||
suggest_clear_text();
|
||||
} else if (do_suggest == 1) {
|
||||
get_suggest_prefix(text);
|
||||
}
|
||||
do_draw= 1;
|
||||
}
|
||||
|
||||
if (do_draw) {
|
||||
ScrArea *sa;
|
||||
|
||||
@ -2223,6 +2391,16 @@ static int check_numbers(char *string)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_identifier(char ch) {
|
||||
if (ch < '0') return 0;
|
||||
if (ch <= '9') return 1;
|
||||
if (ch < 'A') return 0;
|
||||
if (ch <= 'Z' || ch == '_') return 1;
|
||||
if (ch < 'a') return 0;
|
||||
if (ch <= 'z') return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void convert_tabs (struct SpaceText *st, int tab)
|
||||
{
|
||||
Text *text = st->text;
|
||||
|
Loading…
Reference in New Issue
Block a user