Skip to content

Commit

Permalink
Highlight wrong function argument count
Browse files Browse the repository at this point in the history
 * The plug-in now highlights wrong argument counts for function calls
   using the SpellLocal style (green underline). When you hover over the
   highlighted text a tooltip shows the associated warning message.

 * I've cleaned up the actions.tooltip() function a little in the
   process, using the new luainspect.signatures.value_signatures and
   splitting up the function into several distinct parts.

 * Signatures no longer include latin1 text so I removed the workaround.

 * Suffix () to known function type table fields in previews.
  • Loading branch information
xolox committed Aug 12, 2010
1 parent 026fdd4 commit 72a058e
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 47 deletions.
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -10,6 +10,8 @@ The Vim plug-in `luainspect.vim` uses the [LuaInspect](http://lua-users.org/wiki

* If the text cursor is on a variable while the highlighting is refreshed then all occurrences of the variable will be marked in the style of [Vim's cursorline option](http://vimdoc.sourceforge.net/htmldoc/options.html#%27cursorline%27).

* When luainspect reports a wrong argument count for a function call the call will be highlighted with a green underline. When you hover over the highlighted text a tooltip shows the associated warning message.

* When a syntax error is found (during highlighting or using the rename functionality) the lines where the error is reported will be marked like a spelling error.

![Screenshot of semantic highlighting](http://peterodding.com/code/vim/luainspect/screenshot.png)
Expand Down Expand Up @@ -38,6 +40,7 @@ You don't need to use this command unless you've disabled automatic highlighting
* <span style="color: #600000">luaInspectFieldDefined</span>
* <span style="color: #C00000">luaInspectFieldUndefined</span>
* <span style="background: #D3D3D3">luaInspectSelectedVariable</span>
* <span style="border-bottom: 1px dotted green">luaInspectWrongArgCount</span>
* <span style="border-bottom: 1px dotted red">luaInspectSyntaxError</span>

If you don't like one or more of the default styles the Vim documentation [describes how to change them](http://vimdoc.sourceforge.net/htmldoc/syntax.html#:hi-default). If you want to disable the semantic highlighting in a specific Vim buffer execute `:LuaInspect!` in that buffer. When you want to reenable the highlighting execute `:LuaInspect` again, but now without the [bang](http://vimdoc.sourceforge.net/htmldoc/map.html#:command-bang).
Expand Down
2 changes: 1 addition & 1 deletion TODO.md
Expand Up @@ -3,5 +3,5 @@
* Copy highlighting colors for dark backgrounds from luainspect/scite.lua.
* OMNI completion for in scope variables (including display of library function signatures).
* Fix improvised hack by using new `luainspect.signatures.value_signatures` table.
* Highlighting and tooltips for wrong parameter counts.
* Document g:lua_inspect_path option.
* Check whether "core/SciTE: jump to definition now supports functions in different files." is interesting.
13 changes: 8 additions & 5 deletions luainspect.vim
Expand Up @@ -2,7 +2,7 @@
" Author: Peter Odding <peter@peterodding.com>
" Last Change: August 12, 2010
" URL: http://peterodding.com/code/vim/lua-inspect/
" Version: 0.3.5
" Version: 0.3.6
" License: MIT

" Support for automatic update using the GLVS plug-in.
Expand Down Expand Up @@ -52,6 +52,7 @@ let s:groups['FieldDefined'] = 'guifg=#600000'
let s:groups['FieldUndefined'] = 'guifg=#c00000'
let s:groups['SelectedVariable'] = 'CursorLine'
let s:groups['SyntaxError'] = 'SpellBad'
let s:groups['WrongArgCount'] = 'SpellLocal'

" (Automatic) command definitions. {{{1

Expand Down Expand Up @@ -235,12 +236,14 @@ function! s:highlight_variables() " {{{2
call clearmatches()
for line in b:luainspect_output[1:-1]
if s:check_output(line, '^\w\+\(\s\+\d\+\)\{3}$')
let [hlgroup, linenum, firstcol, lastcol] = split(line)
let [group, linenum, firstcol, lastcol] = split(line)
let pattern = s:highlight_position(linenum + 0, firstcol - 1, lastcol + 2)
if hlgroup == 'luaInspectSelectedVariable'
call matchadd(hlgroup, pattern)
if group == 'luaInspectWarning'
call matchadd(group, pattern)
elseif group == 'luaInspectSelectedVariable'
call matchadd(group, pattern, 20)
else
execute 'syntax match' hlgroup '/' . pattern . '/'
execute 'syntax match' group '/' . pattern . '/'
endif
endif
endfor
Expand Down
99 changes: 58 additions & 41 deletions luainspect4vim.lua
Expand Up @@ -15,6 +15,7 @@ local LI = require 'luainspect.init'
local LA = require 'luainspect.ast'
local LS = require 'luainspect.signatures'
local actions, myprint, getcurvar, knownvarorfield = {}
local printvartype, printsignature, printvalue
if type(vim) == 'table' and vim.eval then
-- The Lua interface for Vim redefines print() so it prints inside Vim.
Expand All @@ -26,7 +27,7 @@ else
function myprint(text) io.write(text, '\n') end
end
function getcurvar(tokenlist, line, column)
function getcurvar(tokenlist, line, column) -- {{{1
for i, token in ipairs(tokenlist) do
if token.ast.lineinfo then
local l1, c1 = unpack(token.ast.lineinfo.first, 1, 2)
Expand All @@ -38,57 +39,78 @@ function getcurvar(tokenlist, line, column)
end
end
function knownvarorfield(token)
function knownvarorfield(token) -- {{{1
local a = token.ast
local v = a.seevalue or a
return a.definedglobal or v.valueknown and v.value ~= nil
end
function actions.highlight(tokenlist, line, column)
function actions.highlight(tokenlist, line, column) -- {{{1
local function dump(token, hlgroup)
local l1, c1 = unpack(token.ast.lineinfo.first, 1, 2)
local l2, c2 = unpack(token.ast.lineinfo.last, 1, 2)
myprint(hlgroup .. ' ' .. l1 .. ' ' .. c1 .. ' ' .. c2)
end
local curvar = getcurvar(tokenlist, line, column)
for i, token in ipairs(tokenlist) do
if curvar and curvar.ast.id == token.ast.id then
dump(token, 'luaInspectSelectedVariable')
end
if token.ast.note and token.ast.note:find '[Tt]oo%s+%w+%s+arguments' then
local l1, c1 = unpack(token.ast.lineinfo.first, 1, 2)
local l2, c2 = unpack(token.ast.lineinfo.last, 1, 2)
if l1 == l2 then myprint('luaInspectSelectedVariable ' .. l1 .. ' ' .. c1 .. ' ' .. c2) end
dump(token, 'luaInspectWrongArgCount')
end
local kind
if token.tag == 'Id' then
if not token.ast.localdefinition then
if token.ast.definedglobal then
kind = 'luaInspectGlobalDefined'
else
kind = 'luaInspectGlobalUndefined'
end
dump(token, token.ast.definedglobal and 'luaInspectGlobalDefined' or 'luaInspectGlobalUndefined')
elseif not token.ast.localdefinition.isused then
kind = 'luaInspectLocalUnused'
dump(token, 'luaInspectLocalUnused')
elseif token.ast.localdefinition.functionlevel < token.ast.functionlevel then
kind = 'luaInspectUpValue'
dump(token, 'luaInspectUpValue')
elseif token.ast.localdefinition.isset then
kind = 'luaInspectLocalMutated'
dump(token, 'luaInspectLocalMutated')
elseif token.ast.localdefinition.isparam then
kind = 'luaInspectParam'
dump(token, 'luaInspectParam')
else
kind = 'luaInspectLocal'
dump(token, 'luaInspectLocal')
end
elseif token.ast.isfield then
kind = knownvarorfield(token) and 'luaInspectFieldDefined' or 'luaInspectFieldUndefined'
dump(token, knownvarorfield(token) and 'luaInspectFieldDefined' or 'luaInspectFieldUndefined')
end
if kind then
end
end
function actions.tooltip(tokenlist, line, column) -- {{{1
local did_details = false
for i, token in ipairs(tokenlist) do
if token.ast.lineinfo then
local l1, c1 = unpack(token.ast.lineinfo.first, 1, 2)
local l2, c2 = unpack(token.ast.lineinfo.last, 1, 2)
if l1 == l2 then myprint(kind .. ' ' .. l1 .. ' ' .. c1 .. ' ' .. c2) end
if l1 == line then
local ast = token.ast
if ast and ast.id and column >= c1 and column <= c2 and not did_details then
printvartype(token)
printsignature(ast)
printvalue(ast)
did_details = true
end
if ast.note then
if ast.note:find '[Tt]oo%s+%w+%s+arguments' then
myprint("Warning: " .. ast.note)
else
myprint("Note: " .. ast.note)
end
break
end
end
end
end
end
function actions.tooltip(tokenlist, line, column)
local text = {}
local token = getcurvar(tokenlist, line, column)
if not token then return end
function printvartype(token) -- {{{1
local ast = token.ast
if not ast then return end
-- Describe the variable type and status.
local text = {}
if ast.localdefinition then
if not ast.localdefinition.isused then text[#text+1] = "unused" end
if ast.localdefinition.isset then text[#text+1] = "mutable" end
Expand All @@ -114,22 +136,17 @@ function actions.tooltip(tokenlist, line, column)
-- unknown table field even though table.concat() returns a string?!
text = table.concat(text, ' ')
myprint("This is " .. (text:find '^[aeiou]' and 'an' or 'a') .. ' ' .. text .. '.')
end
function printsignature(ast) -- {{{1
-- Display signatures for standard library functions.
local name = ast.resolvedname
local signature = name and LS.global_signatures[name]
if not signature then
local value = (ast.seevalue or ast).value
for name, sig in pairs(LS.global_signatures) do
if value == loadstring('return ' .. name)() then
signature = sig
end
end
signature = value and LS.value_signatures[value]
end
if signature then
-- luainspect/signatures.lua contains special bullet characters in the
-- latin1 character encoding (according to Vim) which Vim doesn't like
-- in tooltips (I guess because it expects UTF-8).
signature = signature:gsub('\183', '.')
if not signature:find '%w %b()$' then
myprint 'Its description is:'
myprint(' ' .. signature)
Expand All @@ -138,14 +155,17 @@ function actions.tooltip(tokenlist, line, column)
myprint(' ' .. signature)
end
end
end
function printvalue(ast) -- {{{1
-- Try to represent the value as a string.
local value = (ast.seevalue or ast).value
if type(value) == 'table' then
-- Print at most MAX_PREVIEW_KEYS of the table's keys.
local keys = {}
for k, v in pairs(value) do
if type(k) == 'string' then
keys[#keys+1] = k
keys[#keys+1] = k .. (type(v) == 'function' and '()' or '')
elseif type(k) == 'number' then
keys[#keys+1] = '[' .. k .. ']'
else
Expand Down Expand Up @@ -195,14 +215,9 @@ function actions.tooltip(tokenlist, line, column)
elseif value ~= nil then
myprint("Its value is the " .. type(value) .. ' ' .. tostring(value) .. '.')
end
--[[ TODO Print warning notes attached to function calls?
local vast = ast.seevalue or ast
local note = vast.parent and (vast.parent.tag == 'Call' or vast.parent.tag == 'Invoke') and vast.parent.note
if note then myprint("WARNING: " .. note) end
--]]
end
function actions.goto(tokenlist, line, column)
function actions.goto(tokenlist, line, column) -- {{{1
-- FIXME This only jumps to declaration of local / 1st occurrence of global.
local curvar = getcurvar(tokenlist, line, column)
for i, token in ipairs(tokenlist) do
Expand All @@ -215,7 +230,7 @@ function actions.goto(tokenlist, line, column)
end
end
function actions.rename(tokenlist, line, column)
function actions.rename(tokenlist, line, column) -- {{{1
local curvar = getcurvar(tokenlist, line, column)
for i, token in ipairs(tokenlist) do
if curvar and curvar.ast.id == token.ast.id then
Expand All @@ -226,6 +241,8 @@ function actions.rename(tokenlist, line, column)
end
end
-- }}}
return function(src)
local action, line, column, src = src:match '^(%S+)\n(%d+)\n(%d+)\n(.*)$'
line = tonumber(line)
Expand Down

0 comments on commit 72a058e

Please sign in to comment.