[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: autocompletion code
- From: Philippe Lhoste <PhiLho@...>
- Date: Mon, 26 Apr 2004 20:08:15 +0200
Dimitris Papavasiliou wrote:
I've written this code which, given a lua command line in a string (s)
and a cursor position (i) finds all candidate table keys to complete the
command at the position. It completes table indexing expressions of the
form 'table.keyprefix'.
[snip]
Anyway since this is my first attempt at string processing lua code (or
any non-trivial lua code for that matter) I'm sure there are better ways
to do some things. I'm not (particularly) interested in speed, more in
better code. I'm especially looking for better ways to:
a) find the substring I need to parse (the first while loop).
b) if possible when breaking sub into path and prefix use a pattern that
will return "" for path and the whole string sub for prefix if the
string sub contains no dots. Then I can get rid of the if statement
afterwards and use something like table = assert(loadstring("return " ..
path))() or nil instead.
Hey, this is an interesting idea, scanning actual Lua table to search the list of
active members of tables.
Here is your original code, with some comments added (stream comments):
-- the command and cursor position
s = "print(string."
i = string.len(s)
-- scan the string backwards starting at the cursor to find the substring
-- we're interested in (sub)
--[[ Why are you including '\' in the accepted chars? ]]
while string.find(string.sub(s, i, i), "[%w_\.]") do
--[[ Little optimisation on this kind of things: put found chars in an array, and
table.concat them ]]
sub = string.sub(s, i, i) .. (sub or "")
i = i - 1
end
--[[ It seems OK here, but you should avoid to use 'table'
as variable name, as it is the name of a library table...
No need of real variables for returned indexes,
tradition is to use _ as dummy variable. ]]
local i, j, prefix, path, table
-- break a string of the form "foo.bar.pre" into "foo.bar" (path) and
-- "pre" (prefix).
i, j, path, prefix = string.find(sub, "([%w_%.]+)%.([%w_]*)")
-- if there were no dots in the string then the table from wich to complete
-- is _G and the prefix is the whole string
if(path == nil) then
table = _G
prefix = sub
else
-- else get the table represented by path
table = assert(loadstring("return " .. path))()
end
-- now look up all keys in table starting with (but different from) prefix and print them
for k in pairs(table) do
--[[ Perhaps a bit faster, not going the regex route (and avoid two concats)...
len = string.len(prefix) -- Before the loop
if string.sub(k, 1, len) == prefix then
]]
if string.find(k, "^" .. prefix .. ".+") then
print(k)
end
end
Now, my version, where I tried to do some optimisations:
-- the command and cursor position
s = "print(d.string.g"
i = string.len(s)
-- scan the string backwards starting at the cursor to find the substring
-- we're interested in (sub)
while string.find(string.sub(s, i, i), "[%w_\.]") do
i = i - 1
end
sub = string.sub(s, i)
local prefix, path, scantable, len
-- break a string of the form "foo.bar.pre" into "foo.bar" (path) and
-- "pre" (prefix).
_, _, path, prefix = string.find(sub, "([%w_.]-)%.([%w_]*)")
--~ print("-> " .. (path or 'nil') .. '|' .. (prefix or 'nil'))
-- if there were no dots in the string then the table from wich to complete
-- is _G and the prefix is the whole string
if path == nil then
scantable = _G
prefix = sub
else
-- else get the table represented by path
scantable = assert(loadstring("return " .. path))() or {}
end
-- now look up all keys in table starting with (but different from) prefix and print them
len = string.len(prefix)
for k in pairs(table) do
if string.len(k) > len and -- Instantaneous and avoids a number of string extractions
string.sub(k, 1, len) == prefix then
print(k)
end
end
Sorry, I didn't found yet a way to improve the path/prefix regex, but frankly I find
the above test probably clearer than a complex regex and some tricks.
---
Others answers:
Scott wrote:
One thing your code does not consider that can be very helpfull is the use
of the ':' seperator in addition to '.' I wrote something very similar for
the console of our game and I don't remember there being any trick to
getting ':' working. Just check for ':' anywhere you would also look for
'.'
I don't agree, at least in the scope of this snippet.
When you have myFileHandle:o you cannot know what kind of object is myFileHandle, so
you cannot provide efficient autocompletion (ie. only the set of methods applicable
to this object).
Or if you can, I would be interested to know how.
---
Sam wrote:
I tried your piece of code, and I found that your autocompletion forgets an element
when you specify the begining of the string. This element is the string itself.
No, and the comment on the last loop makes this clear: there is no point in listing
the string itself, as there is nothing more to autocomplete...
---
Note: SciTE provides a nice autocompletion support of various language, including
Lua. Autocompletion isn't based on real language, but rather on a list of functions
and parameters.
HTH.
--
--=#=--=#=--=#=--=#=--=#=--=#=--=#=--=#=--=#=--
Philippe Lhoste (Paris -- France)
Professional programmer and amateur artist
http://jove.prohosting.com/~philho/ (outdated)
http://philho.multimania.com (in French, for files to download)
--=#=--=#=--=#=--=#=--=#=--=#=--=#=--=#=--=#=--