{"action":"created","comment":{"url":"https://api.github.com/repos/bfredl/Neovim.jl/pulls/comments/33432865","id":33432865,"diff_hunk":"@@ -0,0 +1,174 @@\n+start_host() = try wait(nvim_child(HostHandler()).reader) end\n+\n+immutable HostHandler\n+    loaded_plugins::Set{String} # plugin file paths\n+    proc_callbacks::Dict{String, Function}\n+end\n+\n+function HostHandler()\n+    HostHandler(Set{String}(), Dict{String, Function}())\n+end\n+\n+# names/methods for invoked cmds/fns have the form:\n+#   <file path>:(command|function|autocmd):<procedure name>\n+function on_notify(h::HostHandler, c, name::String, args::Vector{Any})\n+    proc = require_plug(h, name)\n+\n+    if proc == nothing\n+        throw(ErrorException(name * \" not defined\"))\n+    end\n+\n+    @async(try\n+        proc(c, args...)\n+    catch\n+        throw(MethodError(name, tuple(NvimClient, args...)))\n+        throw(err)\n+    end)\n+end\n+\n+function on_request(h::HostHandler, c, serial, method, args)\n+    if method == \"specs\" # called on UpdateRemotePlugins\n+        reply_result(c, serial, get_specs(args...))\n+    else\n+        proc = require_plug(h, method)\n+\n+        if proc == nothing\n+            reply_error(c, serial, \"Command not defined.\")\n+        end\n+\n+        @async(try\n+            reply_result(c, serial, proc(c, args...))\n+        catch\n+            err = \"No matching method for args (NvimClient, \" * join(args, \", \") * \")\"\n+            reply_error(c, serial, err)\n+        end)\n+    end\n+end\n+\n+function require_plug(h::HostHandler, name::String)\n+    (plugin_file, proc_id) = split(name, ':', 2)\n+\n+    if plugin_file ∉ h.loaded_plugins\n+        cbs = get_callbacks(plugin_file)\n+        merge!(h.proc_callbacks, cbs)\n+    end\n+\n+    get(h.proc_callbacks, name, nothing)\n+end\n+\n+function get_specs(plugin_file)\n+    plugin = nothing\n+    try\n+        plugin = decorate(plugin_file)\n+    end\n+\n+    fn_specs = {}\n+    global plug(proc_type, name, handler, opt_args...) = begin\n+        conf = Dict{String, Any}()\n+        conf[\"type\"] = proc_type\n+        conf[\"name\"] = name\n+        opts = Dict{String, Any}()\n+        for (opt_k, opt_v) in opt_args\n+            opts[string(opt_k)] = opt_v\n+        end\n+        conf[\"opts\"] = opts\n+        conf[\"sync\"] = pop!(opts, \"sync\", 0)\n+        push!(fn_specs, conf)\n+    end\n+\n+    try\n+        eval(plugin)\n+    catch err\n+        println(STDERR, \"Error while loading plugin \" * plugin_file)\n+        println(STDERR, err)\n+    end\n+\n+    fn_specs\n+end\n+\n+function get_callbacks(plugin_file)\n+    plugin = nothing\n+    try\n+        plugin = decorate(plugin_file)\n+    end\n+\n+    proc_callbacks = Array((String, Expr), 0)\n+    global plug(proc_type, name, handler, opt_args...) = begin\n+        pattern = \"\"\n+        for arg in opt_args\n+            if arg[1] == \"pattern\"\n+                pattern = \":\" * arg[2]\n+            end\n+        end\n+\n+        proc_name = \"$plugin_file:$proc_type:$name$pattern\"\n+        push!(proc_callbacks, (proc_name, parse(handler)))\n+    end\n+\n+    try\n+        eval(plugin)\n+    catch err\n+        println(STDERR, \"Error while loading plugin \" * plugin_file)\n+        println(STDERR, err)\n+    end\n+\n+    extract_fns(x) = (x[1], eval(x[2]))\n+    Dict{String, Function}(map(extract_fns, proc_callbacks))\n+end\n+\n+# finds constructs that look like decorators (i.e. macrocall then function)\n+# and then adds the function name as the last argument to the macrocall\n+function decorate(file_name::String)\n+    ast = (open(readall, file_name) |> parse)::Expr\n+    module_name = ast.args[2]\n+\n+    q = Array(Expr, 0)\n+    candidate_fns = Array((Expr, Expr), 0)\n+    push!(q, ast)\n+    while length(q) > 0\n+        expr = shift!(q)\n+        for (i, arg) in enumerate(expr.args)\n+            if typeof(arg) != Expr continue end\n+            if arg.head == :macrocall && expr.args[i + 2].head == :function\n+                # `i + 2` to skip LineNumberNode\n+                fn_name = expr.args[i + 2].args[1].args[1]\n+                push!(arg.args, symbol(\"$module_name.$fn_name\"))","path":"src/plugin_host.jl","position":136,"original_position":135,"commit_id":"298f91fc748dfc6091035959166bc59f7e51bab8","original_commit_id":"7730635ed7b7df3a0478e3d572ac759750e8c7ce","user":{"login":"nhynes","id":2353785,"avatar_url":"https://avatars.githubusercontent.com/u/2353785?v=3","gravatar_id":"","url":"https://api.github.com/users/nhynes","html_url":"https://github.com/nhynes","followers_url":"https://api.github.com/users/nhynes/followers","following_url":"https://api.github.com/users/nhynes/following{/other_user}","gists_url":"https://api.github.com/users/nhynes/gists{/gist_id}","starred_url":"https://api.github.com/users/nhynes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nhynes/subscriptions","organizations_url":"https://api.github.com/users/nhynes/orgs","repos_url":"https://api.github.com/users/nhynes/repos","events_url":"https://api.github.com/users/nhynes/events{/privacy}","received_events_url":"https://api.github.com/users/nhynes/received_events","type":"User","site_admin":false},"body":"I tried playing with a few options. I'll split my findings into macrocall syntax and then the syntax for getting the function name into the macrocall.\r\n\r\n**macrocalls:**\r\n```julia\r\n1. @autocmd BufEnter, pattern=\"*.jl\", sync=false\r\n2. @cmd Rm(args=\"*\")\r\n3. @fn(Random, sync=false)\r\n```\r\nbecomes (in the format {arg1, arg2, arg3})\r\n```julia\r\n1. {(BufEnter, pattern) = (\"*.jl\", sync) = (false,...)}\r\n2. {(Rm(args=\"*\"))}\r\n3. {Random, sync=false}\r\n```\r\nAlthough Option 3 is easiest to handle, the callback name needs to be placed inside of the parens. Although slightly redundant, this allows the plugins to be defined at any location in the file.\r\nOption 2, with a bit of massaging, works fairly well, too. It plays particularly nicely with the `->` syntax (detailed below).\r\n\r\n**callback names**\r\nNow,  as for capturing the function, I looks like `->` and `=`, when used with Option 2, causes the callback to be wrapped in a convenient. I prefer `=` since it's slightly more semantically correct, though I'm open to suggestions.\r\n\r\n**summary**\r\nI think that Option 2 with `=` (i.e. `@cmd Cmd(...) = random()`) is the way to go.\r\n\r\nAlso, I like the brevity of the single-liner in which the function name is the Nvim command name. I think that things might get confusing when Autocmds are thrown into the mix, though.","created_at":"2015-06-29T04:04:15Z","updated_at":"2015-06-29T04:04:15Z","html_url":"https://github.com/bfredl/Neovim.jl/pull/6#discussion_r33432865","pull_request_url":"https://api.github.com/repos/bfredl/Neovim.jl/pulls/6","_links":{"self":{"href":"https://api.github.com/repos/bfredl/Neovim.jl/pulls/comments/33432865"},"html":{"href":"https://github.com/bfredl/Neovim.jl/pull/6#discussion_r33432865"},"pull_request":{"href":"https://api.github.com/repos/bfredl/Neovim.jl/pulls/6"}}},"pull_request":{"url":"https://api.github.com/repos/bfredl/Neovim.jl/pulls/6","id":38608918,"html_url":"https://github.com/bfredl/Neovim.jl/pull/6","diff_url":"https://github.com/bfredl/Neovim.jl/pull/6.diff","patch_url":"https://github.com/bfredl/Neovim.jl/pull/6.patch","issue_url":"https://api.github.com/repos/bfredl/Neovim.jl/issues/6","number":6,"state":"open","locked":false,"title":"Julia plugin host","user":{"login":"nhynes","id":2353785,"avatar_url":"https://avatars.githubusercontent.com/u/2353785?v=3","gravatar_id":"","url":"https://api.github.com/users/nhynes","html_url":"https://github.com/nhynes","followers_url":"https://api.github.com/users/nhynes/followers","following_url":"https://api.github.com/users/nhynes/following{/other_user}","gists_url":"https://api.github.com/users/nhynes/gists{/gist_id}","starred_url":"https://api.github.com/users/nhynes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nhynes/subscriptions","organizations_url":"https://api.github.com/users/nhynes/orgs","repos_url":"https://api.github.com/users/nhynes/repos","events_url":"https://api.github.com/users/nhynes/events{/privacy}","received_events_url":"https://api.github.com/users/nhynes/received_events","type":"User","site_admin":false},"body":"The syntax for plugins is similar to that used for Python except `function` is replaced by `fn` since the former is a reserved word.\r\n\r\nExample plugin: https://gist.github.com/nhynes/41a30e4468f50a044a38","created_at":"2015-06-26T00:59:40Z","updated_at":"2015-06-29T04:04:15Z","closed_at":null,"merged_at":null,"merge_commit_sha":"578781575ad1384deda55cd2e8824a70c3e0b58f","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/bfredl/Neovim.jl/pulls/6/commits","review_comments_url":"https://api.github.com/repos/bfredl/Neovim.jl/pulls/6/comments","review_comment_url":"https://api.github.com/repos/bfredl/Neovim.jl/pulls/comments{/number}","comments_url":"https://api.github.com/repos/bfredl/Neovim.jl/issues/6/comments","statuses_url":"https://api.github.com/repos/bfredl/Neovim.jl/statuses/298f91fc748dfc6091035959166bc59f7e51bab8","head":{"label":"nhynes:pluginhost","ref":"pluginhost","sha":"298f91fc748dfc6091035959166bc59f7e51bab8","user":{"login":"nhynes","id":2353785,"avatar_url":"https://avatars.githubusercontent.com/u/2353785?v=3","gravatar_id":"","url":"https://api.github.com/users/nhynes","html_url":"https://github.com/nhynes","followers_url":"https://api.github.com/users/nhynes/followers","following_url":"https://api.github.com/users/nhynes/following{/other_user}","gists_url":"https://api.github.com/users/nhynes/gists{/gist_id}","starred_url":"https://api.github.com/users/nhynes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nhynes/subscriptions","organizations_url":"https://api.github.com/users/nhynes/orgs","repos_url":"https://api.github.com/users/nhynes/repos","events_url":"https://api.github.com/users/nhynes/events{/privacy}","received_events_url":"https://api.github.com/users/nhynes/received_events","type":"User","site_admin":false},"repo":{"id":36909509,"name":"Neovim.jl","full_name":"nhynes/Neovim.jl","owner":{"login":"nhynes","id":2353785,"avatar_url":"https://avatars.githubusercontent.com/u/2353785?v=3","gravatar_id":"","url":"https://api.github.com/users/nhynes","html_url":"https://github.com/nhynes","followers_url":"https://api.github.com/users/nhynes/followers","following_url":"https://api.github.com/users/nhynes/following{/other_user}","gists_url":"https://api.github.com/users/nhynes/gists{/gist_id}","starred_url":"https://api.github.com/users/nhynes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nhynes/subscriptions","organizations_url":"https://api.github.com/users/nhynes/orgs","repos_url":"https://api.github.com/users/nhynes/repos","events_url":"https://api.github.com/users/nhynes/events{/privacy}","received_events_url":"https://api.github.com/users/nhynes/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/nhynes/Neovim.jl","description":"Neovim client for Julia","fork":true,"url":"https://api.github.com/repos/nhynes/Neovim.jl","forks_url":"https://api.github.com/repos/nhynes/Neovim.jl/forks","keys_url":"https://api.github.com/repos/nhynes/Neovim.jl/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nhynes/Neovim.jl/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nhynes/Neovim.jl/teams","hooks_url":"https://api.github.com/repos/nhynes/Neovim.jl/hooks","issue_events_url":"https://api.github.com/repos/nhynes/Neovim.jl/issues/events{/number}","events_url":"https://api.github.com/repos/nhynes/Neovim.jl/events","assignees_url":"https://api.github.com/repos/nhynes/Neovim.jl/assignees{/user}","branches_url":"https://api.github.com/repos/nhynes/Neovim.jl/branches{/branch}","tags_url":"https://api.github.com/repos/nhynes/Neovim.jl/tags","blobs_url":"https://api.github.com/repos/nhynes/Neovim.jl/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nhynes/Neovim.jl/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nhynes/Neovim.jl/git/refs{/sha}","trees_url":"https://api.github.com/repos/nhynes/Neovim.jl/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nhynes/Neovim.jl/statuses/{sha}","languages_url":"https://api.github.com/repos/nhynes/Neovim.jl/languages","stargazers_url":"https://api.github.com/repos/nhynes/Neovim.jl/stargazers","contributors_url":"https://api.github.com/repos/nhynes/Neovim.jl/contributors","subscribers_url":"https://api.github.com/repos/nhynes/Neovim.jl/subscribers","subscription_url":"https://api.github.com/repos/nhynes/Neovim.jl/subscription","commits_url":"https://api.github.com/repos/nhynes/Neovim.jl/commits{/sha}","git_commits_url":"https://api.github.com/repos/nhynes/Neovim.jl/git/commits{/sha}","comments_url":"https://api.github.com/repos/nhynes/Neovim.jl/comments{/number}","issue_comment_url":"https://api.github.com/repos/nhynes/Neovim.jl/issues/comments{/number}","contents_url":"https://api.github.com/repos/nhynes/Neovim.jl/contents/{+path}","compare_url":"https://api.github.com/repos/nhynes/Neovim.jl/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nhynes/Neovim.jl/merges","archive_url":"https://api.github.com/repos/nhynes/Neovim.jl/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nhynes/Neovim.jl/downloads","issues_url":"https://api.github.com/repos/nhynes/Neovim.jl/issues{/number}","pulls_url":"https://api.github.com/repos/nhynes/Neovim.jl/pulls{/number}","milestones_url":"https://api.github.com/repos/nhynes/Neovim.jl/milestones{/number}","notifications_url":"https://api.github.com/repos/nhynes/Neovim.jl/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nhynes/Neovim.jl/labels{/name}","releases_url":"https://api.github.com/repos/nhynes/Neovim.jl/releases{/id}","created_at":"2015-06-05T03:20:56Z","updated_at":"2015-06-05T03:20:57Z","pushed_at":"2015-06-28T15:53:03Z","git_url":"git://github.com/nhynes/Neovim.jl.git","ssh_url":"git@github.com:nhynes/Neovim.jl.git","clone_url":"https://github.com/nhynes/Neovim.jl.git","svn_url":"https://github.com/nhynes/Neovim.jl","homepage":"","size":183,"stargazers_count":0,"watchers_count":0,"language":"Julia","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"bfredl:master","ref":"master","sha":"4ea71c4f5e17b1cedf87ab8ac79c0e9fcf92ac86","user":{"login":"bfredl","id":1363104,"avatar_url":"https://avatars.githubusercontent.com/u/1363104?v=3","gravatar_id":"","url":"https://api.github.com/users/bfredl","html_url":"https://github.com/bfredl","followers_url":"https://api.github.com/users/bfredl/followers","following_url":"https://api.github.com/users/bfredl/following{/other_user}","gists_url":"https://api.github.com/users/bfredl/gists{/gist_id}","starred_url":"https://api.github.com/users/bfredl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bfredl/subscriptions","organizations_url":"https://api.github.com/users/bfredl/orgs","repos_url":"https://api.github.com/users/bfredl/repos","events_url":"https://api.github.com/users/bfredl/events{/privacy}","received_events_url":"https://api.github.com/users/bfredl/received_events","type":"User","site_admin":false},"repo":{"id":23618057,"name":"Neovim.jl","full_name":"bfredl/Neovim.jl","owner":{"login":"bfredl","id":1363104,"avatar_url":"https://avatars.githubusercontent.com/u/1363104?v=3","gravatar_id":"","url":"https://api.github.com/users/bfredl","html_url":"https://github.com/bfredl","followers_url":"https://api.github.com/users/bfredl/followers","following_url":"https://api.github.com/users/bfredl/following{/other_user}","gists_url":"https://api.github.com/users/bfredl/gists{/gist_id}","starred_url":"https://api.github.com/users/bfredl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bfredl/subscriptions","organizations_url":"https://api.github.com/users/bfredl/orgs","repos_url":"https://api.github.com/users/bfredl/repos","events_url":"https://api.github.com/users/bfredl/events{/privacy}","received_events_url":"https://api.github.com/users/bfredl/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/bfredl/Neovim.jl","description":"Neovim client for Julia","fork":false,"url":"https://api.github.com/repos/bfredl/Neovim.jl","forks_url":"https://api.github.com/repos/bfredl/Neovim.jl/forks","keys_url":"https://api.github.com/repos/bfredl/Neovim.jl/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bfredl/Neovim.jl/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bfredl/Neovim.jl/teams","hooks_url":"https://api.github.com/repos/bfredl/Neovim.jl/hooks","issue_events_url":"https://api.github.com/repos/bfredl/Neovim.jl/issues/events{/number}","events_url":"https://api.github.com/repos/bfredl/Neovim.jl/events","assignees_url":"https://api.github.com/repos/bfredl/Neovim.jl/assignees{/user}","branches_url":"https://api.github.com/repos/bfredl/Neovim.jl/branches{/branch}","tags_url":"https://api.github.com/repos/bfredl/Neovim.jl/tags","blobs_url":"https://api.github.com/repos/bfredl/Neovim.jl/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bfredl/Neovim.jl/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bfredl/Neovim.jl/git/refs{/sha}","trees_url":"https://api.github.com/repos/bfredl/Neovim.jl/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bfredl/Neovim.jl/statuses/{sha}","languages_url":"https://api.github.com/repos/bfredl/Neovim.jl/languages","stargazers_url":"https://api.github.com/repos/bfredl/Neovim.jl/stargazers","contributors_url":"https://api.github.com/repos/bfredl/Neovim.jl/contributors","subscribers_url":"https://api.github.com/repos/bfredl/Neovim.jl/subscribers","subscription_url":"https://api.github.com/repos/bfredl/Neovim.jl/subscription","commits_url":"https://api.github.com/repos/bfredl/Neovim.jl/commits{/sha}","git_commits_url":"https://api.github.com/repos/bfredl/Neovim.jl/git/commits{/sha}","comments_url":"https://api.github.com/repos/bfredl/Neovim.jl/comments{/number}","issue_comment_url":"https://api.github.com/repos/bfredl/Neovim.jl/issues/comments{/number}","contents_url":"https://api.github.com/repos/bfredl/Neovim.jl/contents/{+path}","compare_url":"https://api.github.com/repos/bfredl/Neovim.jl/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bfredl/Neovim.jl/merges","archive_url":"https://api.github.com/repos/bfredl/Neovim.jl/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bfredl/Neovim.jl/downloads","issues_url":"https://api.github.com/repos/bfredl/Neovim.jl/issues{/number}","pulls_url":"https://api.github.com/repos/bfredl/Neovim.jl/pulls{/number}","milestones_url":"https://api.github.com/repos/bfredl/Neovim.jl/milestones{/number}","notifications_url":"https://api.github.com/repos/bfredl/Neovim.jl/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bfredl/Neovim.jl/labels{/name}","releases_url":"https://api.github.com/repos/bfredl/Neovim.jl/releases{/id}","created_at":"2014-09-03T11:42:12Z","updated_at":"2015-04-07T01:06:37Z","pushed_at":"2015-06-28T15:53:04Z","git_url":"git://github.com/bfredl/Neovim.jl.git","ssh_url":"git@github.com:bfredl/Neovim.jl.git","clone_url":"https://github.com/bfredl/Neovim.jl.git","svn_url":"https://github.com/bfredl/Neovim.jl","homepage":"","size":465,"stargazers_count":3,"watchers_count":3,"language":"Julia","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":1,"forks":2,"open_issues":1,"watchers":3,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/bfredl/Neovim.jl/pulls/6"},"html":{"href":"https://github.com/bfredl/Neovim.jl/pull/6"},"issue":{"href":"https://api.github.com/repos/bfredl/Neovim.jl/issues/6"},"comments":{"href":"https://api.github.com/repos/bfredl/Neovim.jl/issues/6/comments"},"review_comments":{"href":"https://api.github.com/repos/bfredl/Neovim.jl/pulls/6/comments"},"review_comment":{"href":"https://api.github.com/repos/bfredl/Neovim.jl/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/bfredl/Neovim.jl/pulls/6/commits"},"statuses":{"href":"https://api.github.com/repos/bfredl/Neovim.jl/statuses/298f91fc748dfc6091035959166bc59f7e51bab8"}}}}