Page 1 of 1

C# Auto-complete for New Objects

Posted: Wed Mar 05, 2014 8:04 am
by jussij
This macro will attempt to auto-complete the C# new statement.

So for example give this code (where | indicates the cursor):

Code: Select all

   private static Dictionary<String, int> fs = new|
On hitting the space bar this macro will auto expand the new to be this code:

Code: Select all

   private static Dictionary<String, int> fs = new Dictionary<String, int>(|);
To use this macro edit the C# document type and in the Templates section add a new template with these details:

Code: Select all

       Keyword: new
     Menu Text: New Autocomplete
Expansion Text: $MacroExcute<auto_new.lua>
The macro code is shown below. That code should be saved to the auto_new.lua file in the Zeus zScript folder.

Code: Select all

--
--        Name: C# New Completion
--
--      Author: Jussi Jumppanen
--
--    Language: Lua Macro
--
-- Description: This macro will try to complete the new keyword by adding
--              the type value automatically.
--
--  How To Run: To use this macro define a template in the C# document
--              type using these values:
--
--                         Keyword: new
--                       Menu Text: new autocomplete
--                  Expansion Text: $MacroExcute<auto_new.lua>
--
function trim(s)
    if s ~= nil then
        -- trim the string
        s = s:gsub("^%s*(.-)%s*$", "%1")
    end
    return s
end

function check_trailing(s)
    -- clean the string
    s = trim(s)

    -- the simple test
    if (s == nil) or (string.len(s) == 0) then
        return true
    end

    -- don't trigger on trailing characters but for some few exceptions
    if string.len(s) == 1 then
        local found = string.find(";)", s)

        if (found ~= nil) then
            -- accept these characters
            return true
        end
    end

    return false
end

-- look for the argument in the statement
function find_argument(statement)
    local argument = nil

    if statement ~= nil then
        statement = trim(statement)

        -- watch out for generic items
        if string.match(statement, "<") ~= nil then
            --
            -- Example: 'private static Dictionary<String, int> fs'
            --
            -- look for the complex case first
            argument = string.match(statement, ".*%s(.*<.*>)%s.+")

            if argument == nil then
                --
                -- Examples: 'Dictionary<String, int> fs'
                --
                -- look for the simpler case
                argument = string.match(statement, "(.*<.*>)%s.+")
            end
        else
            --
            -- Example: 'public static FileStream fs'
            --
            -- look for the complex case first
            argument = string.match(statement, ".*%s(.*)%s.+")

            if argument == nil then
                --
                -- Examples: 'FileStream fs'
                --
                -- look for the simpler case
                argument = string.match(statement, "(.*)%s.+")
            end
        end
    end
    return argument
end

function key_macro()
    -- Typical Examples:
    --    FileStream fs = new FileStream();
    --    public FileStream fs = new FileStream();
    --    private FileStream fs = new FileStream();
    --    public static FileStream fs = new FileStream();
    --    private static FileStream fs = new FileStream();
    --    private static List<String> fs = new List<String>();
    --    private static Dictionary<String, int> fs = new Dictionary<String, int>;
    --
    -- NOTE: For the case of a using case statment we do specail close brace processing.
    --   using (StreamWriter writer = new StreamWriter())
    --
    local line_text = get_line_text();

    -- see if the line contains the 'new' keyword
    local has_new, trailing = string.match(line_text, "^%s*(.*)%s*=%s*new(.*)%s*")

    -- see if we found something and also check the trailing string
    if has_new ~= nil and check_trailing(trailing) == true then
        local argument = nil

        -- look for the argument
        local argument = find_argument(has_new)

        if argument ~= nil and string.len(argument) > 0 then
            local eol = ";"

            -- don't add a semi-colon if it's already there
            if trim(trailing) == ";" then
                eol = ""
            end

            -- watch out for the using case
            if string.match(has_new, "%s*using %(") ~= nil then
                -- remove the errant brace
                argument = string.match(argument, "%((.*)")

                -- set the end of line character but watching out for using
                if string.match(trailing, "%)") ~= nil then
                    eol = ""
                else
                    eol = ")"
                end
            end

            if argument ~= nil and string.len(argument) > 0 then
                if string.sub(argument, -1) == "]" then
                    -- Handle these cases:
                    --    byte[] retByteArr = new;
                    --    byte[] retByteArr = new byte[|];
                    --    byte[,] retByteArr = new;
                    --    byte[,] retByteArr = new byte[|,];

                    -- split the argument at the first open brace
                    head, tail = string.match(argument, "(.*)%[(.*)")

                    if head ~= nil and tail ~= nil then
                        -- position the \c cursor location in the middle of the braces
                        print("new " .. head .. "[\\c" .. tail .. eol)
                    else
                        -- output the details using \c to show the cursor location
                         print("new " .. argument .. eol .. "\\c")
                    end
                else
                    -- output the details using \c to show the cursor location
                    print("new " .. argument .. "(\\c)" .. eol)
                end
            else
                -- write out the trigger
                print("new ")
            end
        else
            -- write out the trigger
            print("new ")
        end
    else
        -- write out the trigger
        print("new ")
    end
end

key_macro() -- run the macro
Cheers Jussi