Hi Lex,

On 2010-07-29 05:20, Lex Trotman wrote:

> I better warn you that it might take a while, the developers are a bit
> overloaded with "real" life at the moment.

No problem, but thanks for the warning anyway.

Well, here's just the next script: It solves the problem that "geany -g"
can only create tag files for one language at a time, but there may be
multiple source code languages present in a project.

This script runs "geany -g" with the correct parameters to generate tag
files for all supported languages for the source files encountered in
the current directory tree.

This script gets its information (which file extensions are supported
for which languages) from parsing the Geany configuration files as well
as reading the directory tree searching for matching source files. It
also sets up CFLAGS automatically to include all directories containing
#include files in sorted breadth-first order.

I have to add that I wrote this script "by mistake" - I did not know
what Geany's "tag-files" are actually used for.

What I expected them to be was something like ctags files; that is, they
would allow me to find a tag declaration everywhere in a project, and
not just in the currently opened files.

But it turned out that "tag" files are actually only used for keyboard
completion and ballon help. ;-)

Cheers,

Guenther
#! /usr/bin/env lua
-- Generate loadable tag files for Geany.
--
-- This script runs "geany -g" with the correct parameters to generate
-- tag files for all supported languages for the source files in the
-- current directory tree.
--
-- This script gets its information from parsing the Geany configuration
-- files as well as reading the directory tree searching for matching
-- source files. It also sets up CFLAGS automatically to include all
-- directories containing #include files in sorted breadth-first order.
--
-- (c) 2010 by Guenther Brunthaler.
--
-- This script is free software.
-- Distribution is permitted under the terms of the GPLv3.


local old_globals= {}; for k in pairs(_G) do old_globals[k]= true; end


local base= "/usr/share/geany"
local includes_xtns= "h H hxx h++ hpp inl"


-- langs[LANGSYM].name == LANGUAGE.
-- langs[LANGSYM].files[INDEX] == RELATIVE_FILENAME.
local langs= {}
local globs= {} -- globs[PATTERN][LANGSYM] == true.
local directs= {} -- directs[STRING][LANGSYM] == true.


local function add_config(filename)
   local section, s, lang, pats, mode, sym, tbl
   for line in io.lines(filename) do
      line= string.match(line, "^%s*(.-)%s*$")
      if line ~= "" and not string.match(line, "^#") then
         s= string.match(line, "^%[([^%]]+)%]$")
         if s then
            section= s
         elseif section == "Extensions" then
            lang, pats= string.match(line, "^([^=]+)%s*=%s*(.-;)$")
            if lang then
               sym= string.lower(lang)
               if not langs[sym] then langs[sym]= {files= {}, name= lang}; end
               for xpat in string.gmatch(pats, "%s*([^;]-)%s*;") do
                  s= string.match(xpat, "^%*([^*]*)$")
                  if s then
                     if s == "" then
                        mode= false
                     else
                        xpat= s
                        mode= "suffix"
                     end
                  else
                     s= string.match(xpat, "^([^*]+)%*$")
                     if s then
                        xpat= s
                        mode= "prefix"
                     else
                        mode=
                           string.match(xpat, "%*") and "complex" or "whole"
                     end
                  end
                  if mode then
                     if mode == "whole" then
                        tbl= directs
                     else
                        tbl= globs
                        xpat= string.gsub(xpat, "([-[%]^(%).*+?$])", "%%%1")
                        if mode == "prefix" then
                           xpat= "^" .. xpat
                        elseif mode == "suffix" then
                           xpat= xpat .. "$"
                        else
                           assert(mode == "complex")
                           xpat= "^" .. string.gsub(xpat, "%%%*", ".*") .. "$"
                        end
                     end
                     if not tbl[xpat] then
                        tbl[xpat]= {}
                     end
                     tbl[xpat][sym]= true
                  end
               end
            else
               io.stderr:write(
                  string.format('Could not parse line "%s"!\n', line)
               )
            end
         end
      end
   end
end


add_config(base .. "/filetype_extensions.conf")
--[[
   do
      local o
      for _, t in
         ipairs{{n= "directs", t= directs}, {n= "globs", t= globs}}
      do
         o= {}
         for k in pairs(t.t) do
            table.insert(o, k)
         end
         table.sort(o)
         for _, k in ipairs(o) do
            o= {}
            for k in pairs(t.t[k]) do
               table.insert(o, string.format("%q", langs[k].name))
            end
            table.sort(o)
            print(
               string.format('%s["%s"] = %s', t.n, k, table.concat(o, ", "))
            )
         end
      end
   end
--]]
local CFLAGS
do
   local idirs= {}
   do
      local xtns= {}
      for xtn in string.gmatch(includes_xtns, "%S+") do xtns[xtn]= true; end

      local m, bn, xt, rfile
      local dir= "find -name '.?*' -type d -prune -o -type f -print"
      dir= assert(io.popen(dir))
      for file in dir:lines() do
         rfile= assert(string.gsub(file, "^%./(.+)$", "%1"))
         bn= string.match(rfile, "[^/]+$")
         xt= string.match(bn, "[^.]*$")
         if xtns[xt] then
            idirs[assert(string.match(file, "(.*)/[^/]*$"))]= true
         end
         m= directs[bn]
         if m then
            for k in pairs(m) do table.insert(langs[k].files, rfile) end
         end
         for pat, plss in pairs(globs) do
            if string.match(bn, pat) then
               for k in pairs(plss) do table.insert(langs[k].files, rfile) end
            end
         end
      end
      assert(dir:close())
   end
   
   local tree= {}
   do
      local base, subpath, current_tree, subtree
      for path in pairs(idirs) do
         current_tree= tree
         repeat
            base, subpath= string.match(path, "^([^/]+)/(.+)")
            if not base then base= path; end
            subtree= current_tree[base]
            if not subtree then
               subtree= {}
               current_tree[base]= subtree
            end
            path, current_tree= subpath, subtree
         until not subpath
      end
   end
   
   local function breadth_first(node, prefix)
      local nn= {}
      for k in pairs(node) do table.insert(nn, k) end
      table.sort(nn)
      for pass= 1, 2 do
         for _, n in ipairs(nn) do
            table.insert(prefix, n)
            if pass == 1 then
               table.insert(idirs, table.concat(prefix, "/"))
            else
               nn= node[n] -- This is the last pass!
               if next(nn) then
                  breadth_first(nn, prefix)
               end
            end
            table.remove(prefix)
         end
      end
   end
   
   idirs= {}
   breadth_first(tree, {})
   do
      local vs
      for k, v in pairs(idirs) do
         vs= string.gsub(v, "^%./(.*)", "%1")
         if vs then v= vs; end
         idirs[k]= string.format(
               string.format(
                     "-I%s"
                  ,  string.match(v, "[%s\"'\\]") and "%q" or "%s"
               )
            ,  v
         )
      end
   end
   CFLAGS= string.format("%q", table.concat(idirs, " "))
end
do
   local function cmp_lang_names(e1, e2)
      return e1.name < e2.name
   end

   local ts= {}
   for k, v in pairs(langs) do
      table.insert(ts, {sym= k, name= v.name, files= v.files})
   end
   table.sort(ts, cmp_lang_names)

   local tagfile, cmd 
   for _, ldsc in ipairs(ts) do
      if next(ldsc.files) then
         tagfile= string.format("name.%s.tags", ldsc.sym)
         print(
            string.format(
                  'Trying to generate tag file "%s" for language "%s".'
               ,  tagfile, ldsc.name
            )
         )
         ts= {string.format("CFLAGS=%s", CFLAGS), "geany", "-g", tagfile}
         for _, file in ipairs(ldsc.files) do
            if string.match(file, "[%s\"'\\]") then
               file= string.format("%q", file)
            end
            table.insert(ts, file)
         end
         cmd= table.concat(ts, " ")
         assert(os.execute(cmd))
      end
   end
end
for k in pairs(_G) do assert(old_globals[k], "created global " .. k) end
_______________________________________________
Geany-devel mailing list
[email protected]
http://lists.uvena.de/cgi-bin/mailman/listinfo/geany-devel

Reply via email to