lbp_completion.cpp
Go to the documentation of this file.
1/*
2********************************************************************
3********************************************************************
4********************************************************************
5
6 Lua completer, derived from Lua advanced readline
7 support patch, with original copyright al follows:
8
9 Copyright (C) 2004-2006 Mike Pall.
10 Same license as Lua. See lua.h.
11
12 The below version is adapted to go with SWIG generated
13 __index functions (as opposed to the perhaps more common
14 __index tables). The interface was changed to a more
15 C++ like style, to make a better match with applications
16 like DESTool. The current implementation is preliminary
17 and requires some clean-up.
18
19 This file is included by lbp_function.cpp and the functions
20 are called by the LuaState methods for completion.
21
22 Thomas Moor, 2011.
23
24********************************************************************
25********************************************************************
26********************************************************************
27*/
28
29#ifndef FAUDES_MUTE_LUA
30
31// Lua keywords
32static const char *const faudes_rl_keywords[] = {
33 "and", "break", "do", "else", "elseif", "end", "false",
34 "for", "function", "if", "in", "local", "nil", "not", "or",
35 "repeat", "return", "then", "true", "until", "while", NULL
36};
37
38// Test identifier
39static bool faudes_rl_valididentifier(const std::string& str) {
40 std::string::const_iterator sit=str.begin();
41 if(sit==str.end()) return false;
42 if(!(isalpha(*sit) || *sit=='_')) return false;
43 for(++sit; sit!=str.end(); ++sit)
44 if(!(isalnum(*sit) || *sit=='_')) return true;
45 return true;
46}
47
48// Append compound prefix + string + suffix to list and maintain common prefix.
49static void faudes_rl_dmadd(std::list< std::string > & mlist, const std::string& prefix, const std::string& str, const std::string& suffix) {
50 // iterate suffxes
51 if(suffix.size()>1) {
52 for(unsigned int i=0;i<suffix.size();i++)
53 faudes_rl_dmadd(mlist,prefix,str,std::string(1,suffix.at(i)));
54 return;
55 }
56 // build compound
57 std::string comp;
58 comp=prefix + str + suffix;
59 // initialize: matching prefix equals first entry
60 if(mlist.size()==0) {
61 mlist.push_back(comp);
62 return;
63 }
64 // initialize: matching prefix equals first entry
65 if(mlist.size()==1) {
66 mlist.push_back(*mlist.begin());
67 mlist.push_back(comp);
68 }
69 // figure maximal matching prefix
70 std::string& match=*mlist.begin();
71 std::string::iterator mit, cit;
72 mit=match.begin();
73 cit=comp.begin();
74 while(mit!=match.end() && cit!=comp.end()) {
75 if(*mit!=*cit) break;
76 mit++; cit++;
77 }
78 // adjust matching prefix in list
79 if(mit!=match.end())
80 match.erase(mit,match.end());
81 // append to list
82 mlist.push_back(comp);
83}
84
85// Get __index field of metatable of object on top of stack
86// -- return 1 for ok and leave __index field on stack
87// -- return 0 for error, nothing on stack
88static int faudes_rl_getmetaindex(lua_State *L) {
89 // object has no metatable, error
90 if(!lua_getmetatable(L, -1))
91 { lua_pop(L, 1); return 0; } // stack:
92 lua_replace(L, -2); // stack: metatable
93 // get the __ index field
94 lua_pushstring(L, "__index");
95 lua_rawget(L, -2); // stack: metatable,__index
96 lua_replace(L, -2); // stack: __index
97 // invald result, error
98 if(lua_isnil(L,-1) || lua_rawequal(L, -1, -2))
99 { lua_pop(L, 1); return 0; } // stack:
100 return 1; // stack: __index
101}
102
103// Get .fn fields of metatable of object on top of stack.
104// -- the SWIG __index function retrieves methods from the .fn attribute
105// -- allways puts a table on the stack, empty on error
106static void faudes_rl_getmetafn(lua_State *L) {
107 // object has no metatable: return empty table
108 if(!lua_getmetatable(L, -1))
109 { lua_pop(L, 1); lua_newtable(L); return; }
110 lua_replace(L, -2); // stack: metatable
111 // get .fn
112 lua_pushstring(L, ".fn");
113 lua_rawget(L, -2); // stack: metatable,.fn
114 lua_replace(L, -2); // stack: .fn
115 if(!lua_istable(L, -1))
116 { lua_pop(L, 1); lua_newtable(L); return; }
117}
118
119// Get .get field of metatable of object on top of stack.
120// -- the SWIG __index function retrieves member access from the .get attribute
121// -- allways puts a table on the stack, empty on error
122static void faudes_rl_getmetaget(lua_State *L) {
123 // object has no metatable: just pop the object
124 if(!lua_getmetatable(L, -1))
125 { lua_pop(L, 1); lua_newtable(L); return; }
126 lua_replace(L, -2); // stack: metatable
127 // get .get
128 lua_pushstring(L, ".get");
129 lua_rawget(L, -2); // stack: metatable,.get
130 lua_replace(L, -2); // stack: .get
131 if(!lua_istable(L, -1))
132 { lua_pop(L, 1); lua_newtable(L); return; }
133}
134
135// Get __index/.fn/.get field of metatable of object on top of stack.
136// -- allways puts a table on stack, empty of error
137// -- returns 1 to indicate ussage of SWIG .get table
138static int faudes_rl_getmeta(lua_State *L, bool has_colon) {
139 // try __index first
140 lua_pushvalue(L,-1); // stack: obj,obj
142 // is it a table // stack: obj,_index
143 if(lua_istable(L,-1)) {
144 // is it non-empty? // stack: obj,_index
145 lua_pushnil(L);
146 if(lua_next(L, -2)) {
147 lua_pop(L, 2); // stack: obj,_index
148 lua_replace(L, -2); // stack: _index
149 return 0;
150 }
151 }
152 lua_pop(L,1); // stack: obj1
153 } // stack: obj
154 // colon indicates method, so we use .fn
155 if(has_colon) {
156 faudes_rl_getmetafn(L); // stack: .fn
157 return 0;
158 }
159 // absence of colon indicates member, so we use .get
160 faudes_rl_getmetaget(L); // stack: .get
161 return 1;
162
163}
164
165
166// Get field from object on top of stack (without calling metamethods)
167static int faudes_rl_getfield(lua_State *L, const char *s, size_t n) {
168 int i = 20; // max loop count to limit infinite metatable loops. */
169 do {
170 if(lua_istable(L, -1)) { // if obj is a table, try to get the requested field
171 lua_pushlstring(L, s, n);
172 lua_rawget(L, -2); // stack: obj,field
173 if(!lua_isnil(L, -1)) // ok, got the field
174 {lua_replace(L, -2); return 1;}
175 lua_pop(L, 1); // stack: obj
176 }
177 if(!faudes_rl_getmetaindex(L)) break; // stack: _index
178 } while (--i > 0);
179 lua_pop(L, 1);
180 return 0;
181} /* 1: obj -- val, 0: obj -- */
182
183
184// actual completer
185static std::list< std::string > faudes_rl_complete(lua_State *L, const std::string& word) {
186
187 // C++ style interface
188 std::list< std::string > mlist;
189 const char* text= word.c_str();
190 int start=0;
191 int end=word.size();
192
193 // other locals
194 const char *s;
195 size_t i, n, dot, loop;
196 int colon;
197 int savetop;
198 bool used_swig_get=false;
199
200 // bail out on text that cannot complete to an identifier
201 if (!(text[0] == '\0' || isalpha(text[0]) || text[0] == '_')) return mlist;
202
203 // record top of stack
204 savetop = lua_gettop(L);
205
206 // figure the right most complete field in "word" and
207 // -- leave the table of globals on the stack, if there is no complete field
208 lua_pushglobaltable(L);
209 for(n = (size_t)(end-start), i = dot = 0, colon=-1; i < n; i++) {
210 if(text[i] == '.' || text[i] == ':') {
211 if(!faudes_rl_getfield(L, text+dot, i-dot))
212 { lua_settop(L, savetop); return mlist; } // error
213 dot = i+1; // Points to first char after dot/colon.
214 if(text[i] == ':') colon=dot; // record whether we have seen a colon
215 }
216 }
217
218 // Append all matches against keywords if there is no dot/colon.
219 if(dot == 0)
220 for (i = 0; (s = faudes_rl_keywords[i]) != NULL; i++)
221 if(!strncmp(s, text, n)) faudes_rl_dmadd(mlist, "", std::string(s), " ");
222
223 // Append all valid matches from all tables/metatables.
224 loop = 0; // Avoid infinite metatable loops.
225 do {
226 if(lua_istable(L, -1))
227 if((loop == 0 || 1 /* !lua_rawequal(L, -1, LUA_GLOBALSINDEX) */) ) { // TODO: this used to be Lua 5.1.3 .. what todo with Lua 5.4.8?
228 for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
229 if (lua_type(L, -2) == LUA_TSTRING) {
230 s = lua_tostring(L, -2);
231 // Only match names starting with '_' if explicitly requested.
232 if (!strncmp(s, text+dot, n-dot) && faudes_rl_valididentifier(s) &&
233 (*s != '_' || text[dot] == '_')) {
234 std::string suf = " "; // Default suffix is a space.
235 switch (lua_type(L, -1)) {
236 case LUA_TTABLE: suf = ":."; break;
237 case LUA_TFUNCTION: if(!used_swig_get) suf = "("; break;
238 case LUA_TUSERDATA:
239 if (lua_getmetatable(L, -1)) { lua_pop(L, 1); suf = ":."; }
240 break;
241 }
242 faudes_rl_dmadd(mlist, std::string(text,dot), std::string(s), suf);
243 }
244 }
245 }
246 }
247 used_swig_get = faudes_rl_getmeta(L,colon>0);
248 } while (++loop < 20);
249
250 // Fix stack
251 lua_settop(L, savetop);
252
253 // done
254 return mlist;
255}
256
257#endif
static int faudes_rl_getmetaindex(lua_State *L)
static std::list< std::string > faudes_rl_complete(lua_State *L, const std::string &word)
static int faudes_rl_getfield(lua_State *L, const char *s, size_t n)
static void faudes_rl_getmetafn(lua_State *L)
static int faudes_rl_getmeta(lua_State *L, bool has_colon)
static const char *const faudes_rl_keywords[]
static void faudes_rl_dmadd(std::list< std::string > &mlist, const std::string &prefix, const std::string &str, const std::string &suffix)
static bool faudes_rl_valididentifier(const std::string &str)
static void faudes_rl_getmetaget(lua_State *L)

libFAUDES 2.34d --- 2026.03.11 --- c++ api documentaion by doxygen