lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Romulo wrote:
As you mentioned it.. does anyone know if there any effort to bring
contextual highlighting to vim's Lua file type plugin? I've never done
any vim plugin, so I am clueless about how difficult it might be.

Inspired by this thread, I've just published the first prototype of a Vim plug-in that uses LuaInspect to (automatically) perform semantic highlighting of variables in Lua buffers. You can find installation instructions for the plug-in at http://peterodding.com/code/vim/lua-inspect/#installation

 - Peter Odding
" Vim plug-in
" Author: Peter Odding <peter@peterodding.com>
" Last Change: July 27, 2010
" URL: http://peterodding.com/code/vim/lua-inspect/
" Version: 0.1.2

" Configuration defaults. {{{1

if !exists('g:lua_inspect_automatic')
  " Set this to false (0) to disable the automatic command.
  let g:lua_inspect_automatic = 1
endif

if !exists('g:lua_inspect_internal')
  " Set this to false (0) to run LuaInspect inside the Lua interface for Vim.
  " This makes it faster but less accurate because the Lua interface for Vim
  " doesn't include io.* and half of os.* which means LuaInspect marks them as
  " undefined globals...
  let g:lua_inspect_internal = 0
endif

" (Automatic) command definitions. {{{1

command! LuaInspect call s:RunLuaInspect()

augroup PluginLuaInspect
  autocmd! CursorHold,CursorHoldI * call s:AutoEnable()
augroup END

" Script local functions. {{{1

function! s:AutoEnable()
  if &filetype == 'lua' && g:lua_inspect_automatic
    LuaInspect
  end
endfunction

function! s:RunLuaInspect()
  let l:text = join(getline(1, "$"), "\n")
  if has('lua') && g:lua_inspect_internal
    " Run LuaInspect using the Lua interface for Vim.
    redir => listing
    silent lua << EOF
    if io == nil then
      -- The Lua interface for Vim doesn't include io.*!
      io = { type = function() end }
    end
    require 'luainspect4vim' (vim.eval 'l:text')
EOF
    redir END
  else
    " Run LuaInspect as an external program.
    let listing = system("lua -e 'require\"luainspect4vim\" (io.read \"*a\")'", l:text)
  endif
  " Clear previously created highlighting.
  call s:InitHighlighting()
  " Highlight variables in buffer based on positions.
  for fields in split(listing, "\n")
    let [type, lnum, start, end] = split(fields)
    let command = 'syntax match %s /\%%%il\%%>%ic.\+\%%<%ic/'
    execute printf(command, type, lnum, start - 1, end + 2)
  endfor
endfunction

function! s:InitHighlighting()
  " Clear existing highlighting.
  if hlexists('luaInspectGlobalDefined') | syntax clear luaInspectGlobalDefined | endif
  if hlexists('luaInspectGlobalUndefined') | syntax clear luaInspectGlobalUndefined | endif
  if hlexists('luaInspectLocalUnused') | syntax clear luaInspectLocalUnused | endif
  if hlexists('luaInspectLocalMutated') | syntax clear luaInspectLocalMutated | endif
  if hlexists('luaInspectUpValue') | syntax clear luaInspectUpValue | endif
  if hlexists('luaInspectParam') | syntax clear luaInspectParam | endif
  if hlexists('luaInspectLocal') | syntax clear luaInspectLocal | endif
  if hlexists('luaInspectFieldDefined') | syntax clear luaInspectFieldDefined | endif
  if hlexists('luaInspectFieldUndefined') | syntax clear luaInspectFieldUndefined | endif
  " Define default styles (copied from /luainspect/scite.lua for consistency).
  hi luaInspectGlobalDefined guifg=#600000
  hi def link luaInspectGlobalUndefined WarningMsg
  hi luaInspectLocalUnused guifg=#ffffff guibg=#0000ff
  hi luaInspectLocalMutated gui=italic guifg=#000080
  hi luaInspectUpValue guifg=#0000ff
  hi luaInspectParam guifg=#000040
  hi luaInspectLocal guifg=#000080
  hi luaInspectFieldDefined guifg=#600000
  hi luaInspectFieldUndefined guifg=#c00000
  " TODO Consider the &background?
endfunction

" vim: ts=2 sw=2 et
--[[

 This module is part of the luainspect.vim plug-in for the Vim text editor.

 Author: Peter Odding <peter@peterodding.com>
 Last Change: July 27, 2010
 URL: http://peterodding.com/code/vim/lua-inspect/

--]]

local function offset2lineinfo(text, offset)
  -- TODO Cache intermediate results because they won't change within a single
  --      call to the function returned from this module below.
  local curlnum = 1
  local lastlineoffset = 0
  for i in text:gmatch '()\n' do
    if i < offset then
      curlnum = curlnum + 1
      lastlineoffset = i
    else
      break
    end
  end
  return curlnum, offset - lastlineoffset
end

return function(text)
  -- Load the LuaInspect core module.
  local LI = require 'luainspect.init'
  text = LI.remove_shebang(text)
  local f, err, linenum, colnum, linenum2 = LI.loadstring(text)
  local function dumpvar(kind, firstbyte, lastbyte)
    local line1, offset1 = offset2lineinfo(text, firstbyte)
    if type(vim) == 'table' and vim.eval then
      -- The Lua interface for Vim redefines print() so it prints inside Vim.
      print(kind, line1, offset1, offset1 + (lastbyte - firstbyte))
    else
      -- My $LUA_INIT script redefines print() to enable pretty printing in the
      -- interactive prompt, which means strings are printed with surrounding
      -- quotes. This would break the communication between Vim and this script.
      io.write(kind, '\t', line1, '\t', offset1, '\t', offset1 + (lastbyte - firstbyte), '\n')
    end
  end
  if f then
    local ast; ast, err, linenum, colnum, linenum2 = LI.ast_from_string(text, "noname.lua")
    if ast then
      for i, note in ipairs(LI.inspect(ast)) do
        if note.type == 'global' then
          if note.definedglobal then
            dumpvar('luaInspectGlobalDefined', note[1], note[2])
          else
            dumpvar('luaInspectGlobalUndefined', note[1], note[2])
          end
        elseif note.type == 'local' then
          if not note.ast.localdefinition.isused then
            dumpvar('luaInspectLocalUnused', note[1], note[2])
          elseif note.ast.localdefinition.isset then
            dumpvar('luaInspectLocalMutated', note[1], note[2])
          elseif note.ast.localdefinition.functionlevel  < note.ast.functionlevel then
            dumpvar('luaInspectUpValue', note[1], note[2])
          elseif note.ast.localdefinition.isparam then
            dumpvar('luaInspectParam', note[1], note[2])
          else
            dumpvar('luaInspectLocal', note[1], note[2])
          end
        elseif note.type == 'field' then
          if note.definedglobal or note.ast.seevalue.value ~= nil then
            dumpvar('luaInspectFieldDefined', note[1], note[2])
          else
            dumpvar('luaInspectFieldUndefined', note[1], note[2])
          end
        end
      end
    end
  end
end

-- vim: ts=2 sw=2 et