-- Copyright 2007-2017 Mitchell mitchell.att.foicica.com. See LICENSE.

local M = {}

--[[ This comment is for LuaDoc.
---
-- The php module.
-- It provides utilities for editing PHP code.
module('_M.php')]]

-- Load HTML Autocompletion and documentation.
if not _M.html then _M.html = require('html') end

-- Sets default buffer properties for PHP files.
events.connect(events.LEXER_LOADED, function(lang)
  if lang == 'php' then
    buffer.word_chars =
      'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_'
  end
end)

---
-- List of ctags files to use for autocompletion.
-- @class table
-- @name tags
M.tags = {_HOME..'/modules/php/tags', _USERHOME..'/modules/php/tags'}


-- Autocompletion and documentation.

local completion = '%s'..string.char(buffer.auto_c_type_separator)..'%d'
local XPM = textadept.editing.XPM_IMAGES
local xpms = {
  c = XPM.CLASS, f = XPM.METHOD, m = XPM.VARIABLE, M = XPM.STRUCT,
  v = XPM.VARIABLE
}


textadept.editing.autocompleters.php = function()
  local list = {}
  -- Retrieve the symbol behind the caret.
  local line, pos = buffer:get_cur_line()
  local symbol, op, part = line:sub(1, pos):match('([%w_%.]-)(%.?)([%w_]*)$')
  if symbol == '' and part == '' then return nil end -- nothing to complete
  -- Attempt to identify the symbol type.
  -- TODO: identify literals like "'foo'." and "[1, 2, 3].".
  local buffer = buffer
  local assignment = '%f[%w_]'..symbol:gsub('(%p)', '%%%1')..'%s*=%s*(.*)$'
  for i = buffer:line_from_position(buffer.current_pos) - 1, 0, -1 do
    local expr = buffer:get_line(i):match(assignment)
    if expr then
      for patt, type in pairs(M.expr_types) do
        if expr:find(patt) then symbol = type break end
      end
      if expr:find('^[%u][%w_.]*%s*%b()%s*$') then
        symbol = expr:match('^([%u][%w_.]+)%s*%b()%s*$') -- e.g. a = Foo()
        break
      end
    end
  end
  -- Search through ctags for completions for that symbol.
  local name_patt = '^'..part
  local sep = string.char(buffer.auto_c_type_separator)
  for i = 1, #M.tags do
    if lfs.attributes(M.tags[i]) then
      for line in io.lines(M.tags[i]) do
        local name = line:match('^%S+')
        if name:find(name_patt) and not list[name] then
          local fields = line:match(';"\t(.*)$')
          local k, class = fields:sub(1, 1), fields:match('class:(%S+)') or ''
          if class == symbol and (op ~= ':' or k == 'f') then
            list[#list + 1] = ("%s%s%d"):format(name, sep, xpms[k])
            list[name] = true
          end
        end
      end
    end
  end
  return #part, list
end

textadept.editing.api_files.php = {
  _HOME..'/modules/php/api', _USERHOME..'/modules/php/api'
}

-- Commands.

---
-- Container for PHP-specific key bindings.
-- @class table
-- @name _G.keys.php
keys.php = {
  ['s\n'] = function()
    buffer:line_end()
    buffer:add_text(';')
    buffer:new_line()
  end,
}

-- Snippets.

if type(snippets) == 'table' then
---
-- Container for PHP-specific snippets.
-- @class table
-- @name _G.snippets.php
  snippets.php = {
    ['php'] = '<?php\n%0\n?>',
    ['if'] = 'if (%1(logic)) {\n\t%0(# code...)\n}',
    ['for'] = 'for ($%1(i)=0; $%1 < %2; $%1++) {\n\t%0(# code...)\n}',
    ['foreach'] = 'foreach ($%1(variable) as $%2(key)%3( => %4($value))) {\n\t%0(# code...)\n}',
    ['echo'] = "echo '%1(test)';%0",
    ['function'] = 'function %1(function_name)(%2) {\n\t%0(# code...)\n}',
    ['class'] = 'class %1(AClass) %2(extends %3(AnotherClass)) {\n\tfunction __construct(%4(argument)) {\n\t\t%0(// code)\n\t}\n}',
    ['/**'] = '/**\n * %0\n */',
  }
end

return M
