aboutsummaryrefslogblamecommitdiffstats
path: root/edconf.lua
blob: 2ec800b424d2ce86145f114f9067dc58b4053482 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
             
                           













                                               

















                                                       



                                                                     





                                                      
                                             







                                                               
                                             







                                                           
                                             










                                                                       
                                             

















                                                                

                                 
                                            











                                                           




























                                                                       
                         
              

                    


                      
                                               





























                                                                                     
                          
    




                                                          
require "vis"
ec = require "editorconfig"

-- Simple wrapper
function vis_set(option, value)
  if type(value) == "boolean" then
    if value then
      value = "yes"
    else
      value = "no"
    end
  end

  vis:command("set " .. option .. " " .. value)
end

function set_pre_save(f, value)
  if value == "true" then
    vis.events.subscribe(vis.events.FILE_SAVE_PRE, f)
  else
    vis.events.unsubscribe(vis.events.FILE_SAVE_PRE, f)
  end
end

function set_file_open(f, value)
  if value == "true" then
    vis.events.subscribe(vis.events.FILE_OPEN, f)
  else
    vis.events.unsubscribe(vis.events.FILE_OPEN, f)
  end
end

-- Custom functionality
function insert_final_newline(file, path)
  -- Technically speaking, this is a pre-save-hook as well and could
  -- therefore respect edconf_hooks_enabled. Since this function runs
  -- blazingly fast and scales with a complexity of O(1), however,
  -- there is no need to disable it.
  if file:content(file.size-1, file.size) ~= '\n' then
    file:insert(file.size, '\n')
  end
end

function trim_trailing_whitespace(file, path)
  if not edconf_hooks_enabled then return end
  for i=1, #file.lines do
    if string.match(file.lines[i], '[ \t]$') then
      file.lines[i] = string.gsub(file.lines[i], '[ \t]*$', '')
    end
  end
end

function enforce_crlf_eol(file, path)
  if not edconf_hooks_enabled then return end
  for i=1, #file.lines do
    if not string.match(file.lines[i], '\r$') then
      file.lines[i] = string.gsub(file.lines[i], '$', '\r')
    end
  end
end

function enforce_lf_eol(file, path)
  if not edconf_hooks_enabled then return end
  for i=1, #file.lines do
    if string.match(file.lines[i], '\r$') then
      file.lines[i] = string.gsub(file.lines[i], '\r$', '')
    end
  end
end

global_max_line_length = 80     -- This is ugly, but we do want to use
                                -- single function that we can register
                                -- or unregister as needed
function max_line_length(file, path)
  if not edconf_hooks_enabled then return end
  local overlong_lines = {}
  for i=1, #file.lines do
    if string.len(file.lines[i]) > global_max_line_length then
      table.insert(overlong_lines, i)
    end
  end
  if #overlong_lines > 0 then
    local lines_are = (function(x)
        if x>1 then return "lines are" else return "line is" end
    end)(#overlong_lines)
    vis:info(string.format(
      "%d %s longer than %d characters: %s",
      #overlong_lines, lines_are, global_max_line_length,
      table.concat(overlong_lines, ",")
    ))
  end
end

OPTIONS = {
  indent_style = function (value)
    vis_set("expandtab", (value == "space"))
  end,

  indent_size = function (value)
    if value ~= "tab" then -- tab_width is a synonym anyway
      vis_set("tabwidth", value)
    end
  end,

  tab_width = function (value)
    vis_set("tabwidth", value)
  end,

  insert_final_newline = function (value)
    set_pre_save(insert_final_newline, value)
  end,

  trim_trailing_whitespace = function (value)
    set_pre_save(trim_trailing_whitespace, value)
  end,

  -- End of line is only partially implemented. While vis does not
  -- support customized newlines, it does work well enough with crlf
  -- newlines. Therefore, setting end_of_line=crlf will just ensure
  -- that there is a cr at the end of each line. Setting end_of_line=lf
  -- will strip any cr characters at the end of lines. This hopefully
  -- eases the pain of working with crlf files a little.
  end_of_line = function (value)
    set_pre_save(enforce_crlf_eol, tostring(value == "crlf"))
    set_pre_save(enforce_lf_eol, tostring(value == "lf"))
  end,

  -- There is probably no straightforward way to enforce a maximum line
  -- length across different programming languages. If a maximum line
  -- length is set, we can at least issue a warning, however.
  max_line_length = function(value)
    if value ~= "off" then
      global_max_line_length = tonumber(value)
    end
    set_pre_save(max_line_length, tostring(value ~= "off"))
  end,

  -- Not supported by vis
  --   charset
  -- Partial support
  --   end_of_line
  --   max_line_length
}

-- Compatible with editorconfig-core-lua v0.3.0
function ec_iter(p)
  i = 0
  props, keys = ec.parse(p)
  n = #keys
  return function ()
    i = i + 1
    if i <= n then
      return keys[i], props[keys[i]]
    end
  end
end

function ec_set_values(path)
  if path then
    for name, value in ec_iter(path) do
      if OPTIONS[name] then
        OPTIONS[name](value)
      end
    end
  end
end

function ec_parse_cmd() ec_set_values(vis.win.file.path) end
vis:command_register("econfig_parse", ec_parse_cmd, "(Re)parse an editorconfig file")

vis.events.subscribe(vis.events.FILE_OPEN, function (file)
  ec_set_values(file.path)
end)

vis.events.subscribe(vis.events.FILE_SAVE_POST, function (file, path)
  ec_set_values(file.path)
end)

edconf_hooks_enabled = false
vis:option_register("edconfhooks", "bool", function(value)
  edconf_hooks_enabled = value
end)