martanne / vis

A vi-like editor based on Plan 9's structural regular expressions
Other
4.19k stars 260 forks source link

[Plugin] Dvorak-friendly Remappings #1184

Closed VehementHam closed 1 month ago

VehementHam commented 2 months ago

What feature would you like to see?

As a user of the Dvorak keyboard layout, I hate how everything is designed for QWERTY. I have gone ahead and remapped the keys in almost every application that I use to better fit the Dvorak keyboard layout.

Here is what I did to Vis:

I am having trouble re-adding descriptions to the bindings. That is WIP.

The code for rebinding in this way is as follows:


-- ...

vis.events.subscribe(vis.events.INIT, function()
    -- Your global configuration options

    -- Dvorak-friendly Remappings

    -- key unmapppings
    vis:unmap(vis.modes.NORMAL, "<M-C-j>")
    vis:unmap(vis.modes.NORMAL, "<M-C-k")
    vis:unmap(vis.modes.NORMAL, "<C-w>j")
    vis:unmap(vis.modes.NORMAL, "gj")
    vis:unmap(vis.modes.NORMAL, "gJ")

    vis:unmap(vis.modes.OPERATOR_PENDING, "j")
    vis:unmap(vis.modes.OPERATOR_PENDING, "il")
    vis:unmap(vis.modes.OPERATOR_PENDING, "al")
    vis:unmap(vis.modes.OPERATOR_PENDING, "gj")

    vis:unmap(vis.modes.VISUAL, "<C-j>")
    vis:unmap(vis.modes.VISUAL, "il")
    vis:unmap(vis.modes.VISUAL, "al")
    vis:unmap(vis.modes.VISUAL, "gj")
    vis:unmap(vis.modes.NORMAL, "gJ")

    -- key mappings -- followed by bind it replaces
    vis:map(vis.modes.NORMAL, "d", "<vis-motion-char-prev>") -- h
    vis:map(vis.modes.NORMAL, "h", "<vis-motion-line-down>") -- j
    vis:map(vis.modes.NORMAL, "t", "<vis-motion-line-up>") -- k
    vis:map(vis.modes.NORMAL, "n", "<vis-motion-char-next>") -- l
    vis:map(vis.modes.NORMAL, "D", "<vis-motion-window-line-top>") -- H
    vis:map(vis.modes.NORMAL, "H", "<vis-join-lines>") -- J
    vis:map(vis.modes.NORMAL, "N", "<vis-motion-window-line-bottom>") -- L
    vis:map(vis.modes.NORMAL, "l", "<vis-motion-search-repeat>") -- n
    vis:map(vis.modes.NORMAL, "L", "<vis-motion-search-repeat-backward>") -- N
    vis:map(vis.modes.NORMAL, "k", "<vis-operator-delete>") -- d
    vis:map(vis.modes.NORMAL, "K", "k$") -- D, d$
    vis:map(vis.modes.NORMAL, "<M-C-h>", "<vis-new-selection-lines-below-last>") -- <M-C-j>
    vis:map(vis.modes.NORMAL, "<M-C-t>", "<vis-new-selection-lines-above-first>") -- <M-C-k>
    vis:map(vis.modes.NORMAL, "<C-w>d", "<C-w>t") -- <C-w>h, <C-w>k
    vis:map(vis.modes.NORMAL, "<C-w>h", "<vis-window-next>") -- <C-w>j
    vis:map(vis.modes.NORMAL, "<C-w>t", "<vis-window-prev>") -- <C-w>k
    vis:map(vis.modes.NORMAL, "<C-w>n", "<C-w>h") -- <C-w>l, <C-w>j
    vis:map(vis.modes.NORMAL, "<C-w>l", ":open<Enter>") -- <C-w>n
    vis:map(vis.modes.NORMAL, "<C-h>", "<new-selection-lines-below>") -- <C-j>
    vis:map(vis.modes.NORMAL, "<C-t>", "<new-selection-lines-above>") -- <C-k>
    vis:map(vis.modes.NORMAL, "<C-n>", "<vis-selections-remove-column-except>") -- <C-l>
    vis:map(vis.modes.NORMAL, "<C-k>", "<vis-selection-next>") -- <C-d>
    vis:map(vis.modes.NORMAL, "<C-l>", "viw") -- <C-n>
    vis:map(vis.modes.NORMAL, "+", "h^") -- +, j^
    vis:map(vis.modes.NORMAL, "-", "t^") -- -, k^
    vis:map(vis.modes.NORMAL, "X", "kd") -- X, dh
    vis:map(vis.modes.NORMAL, "s", "cn") -- s, cl
    vis:map(vis.modes.NORMAL, "gD", "<vis-motion-byte-left>") -- gH
    vis:map(vis.modes.NORMAL, "gH", "<vis-join-lines-trim>") -- gJ
    vis:map(vis.modes.NORMAL, "gN", "<vis-motion-byte-right>") -- gL
    vis:map(vis.modes.NORMAL, "gL", "vgL") -- gN, vgN
    vis:map(vis.modes.NORMAL, "gd", "<vis-motion-codepoint-prev>") -- gh
    vis:map(vis.modes.NORMAL, "gh", "<vis-motion-screenline-down>") -- gj
    vis:map(vis.modes.NORMAL, "gt", "<vis-motion-screenline-up>") -- gk
    vis:map(vis.modes.NORMAL, "gn", "<vis-motion-codepoint-next>") -- gl
    vis:map(vis.modes.NORMAL, "gl", "vgl") -- gn, vgn
    vis:map(vis.modes.NORMAL, "j", "vis-motion-till-line-right") -- t
    vis:map(vis.modes.NORMAL, "J", "vis-motion-till-line-left") -- T

    vis:map(vis.modes.OPERATOR_PENDING, "k", "<vis-operator-delete>") -- d
    vis:map(vis.modes.OPERATOR_PENDING, "d", "<vis-motion-char-prev>") -- h
    vis:map(vis.modes.OPERATOR_PENDING, "h", "<vis-motion-line-down>") -- j
    vis:map(vis.modes.OPERATOR_PENDING, "t", "<vis-motion-line-up>") -- k
    vis:map(vis.modes.OPERATOR_PENDING, "n", "<vis-motion-char-next>")  -- l
    vis:map(vis.modes.OPERATOR_PENDING, "D", "<vis-motion-window-line-top>") -- H
    vis:map(vis.modes.OPERATOR_PENDING, "N", "<vis-motion-window-line-bottom>") -- L
    vis:map(vis.modes.OPERATOR_PENDING, "l", "<vis-motion-search-repeat>") -- n
    vis:map(vis.modes.OPERATOR_PENDING, "L", "<vis-motion-search-repeat-backward>") -- N
    vis:map(vis.modes.OPERATOR_PENDING, "in", "<vis-textobject-line-inner>") -- il
    vis:map(vis.modes.OPERATOR_PENDING, "an", "<vis-textobject-line-outer>") -- al
    vis:map(vis.modes.OPERATOR_PENDING, "+", "h^") -- +, j^
    vis:map(vis.modes.OPERATOR_PENDING, "-", "t^") -- -, k^
    vis:map(vis.modes.OPERATOR_PENDING, "gD", "<vis-motion-byte-left>") -- gH
    vis:map(vis.modes.OPERATOR_PENDING, "gN", "<vis-motion-byte-right>") -- gL
    vis:map(vis.modes.OPERATOR_PENDING, "gL", "<vis-textobject-search-backward>") -- gN
    vis:map(vis.modes.OPERATOR_PENDING, "gd", "<vis-motion-codepoint-prev>") -- gh
    vis:map(vis.modes.OPERATOR_PENDING, "gh", "<vis-motion-screenline-down>") -- gj
    vis:map(vis.modes.OPERATOR_PENDING, "gt", "<vis-motion-screenline-up>") -- gk
    vis:map(vis.modes.OPERATOR_PENDING, "gn", "<vis-motion-codepoint-next>") -- gl
    vis:map(vis.modes.OPERATOR_PENDING, "gl", "<vis-textobject-search-forward>") -- gn
    vis:map(vis.modes.OPERATOR_PENDING, "j", "vis-motion-till-line-right") -- t
    vis:map(vis.modes.OPERATOR_PENDING, "J", "vis-motion-till-line-left") -- T

    vis:map(vis.modes.VISUAL, "d", "<vis-motion-char-prev>") -- h
    vis:map(vis.modes.VISUAL, "h", "<vis-motion-line-down>") -- j
    vis:map(vis.modes.VISUAL, "t", "<vis-motion-line-up>") -- k
    vis:map(vis.modes.VISUAL, "n", "<vis-motion-char-next>") -- l
    vis:map(vis.modes.VISUAL, "D", "<vis-motion-window-line-top>") -- H
    vis:map(vis.modes.VISUAL, "H", "<vis-join-lines>") -- J
    vis:map(vis.modes.VISUAL, "N", "<vis-motion-window-line-bottom>") -- L
    vis:map(vis.modes.VISUAL, "l", "<vis-motion-search-repeat>") -- n
    vis:map(vis.modes.VISUAL, "L", "<vis-motion-search-repeat-backward>") -- N
    vis:map(vis.modes.VISUAL, "k", "<vis-operator-delete>") -- d
    vis:map(vis.modes.VISUAL, "<C-h>", "<C-k>") -- <C-j>, <C-d>
    vis:map(vis.modes.VISUAL, "<C-t>", "<C-u>") -- <C-k>
    vis:map(vis.modes.VISUAL, "<C-n>", "<vis-selections-remove-column-except>") -- <C-l>
    vis:map(vis.modes.VISUAL, "<C-l>", "<vis-selection-new-match-next>") -- <C-n>
    vis:map(vis.modes.VISUAL, "<C-k>", "<vis-selection-next>") -- <C-d>
    vis:map(vis.modes.VISUAL, "in", "<vis-textobject-line-inner>") -- il
    vis:map(vis.modes.VISUAL, "an", "<vis-textobject-line-outer>") -- al
    vis:map(vis.modes.VISUAL, "x", "k") -- x, d
    vis:map(vis.modes.VISUAL, "gD", "<vis-motion-byte-left>") -- gH
    vis:map(vis.modes.VISUAL, "gH", "<vis-join-lines-trim>") -- gJ
    vis:map(vis.modes.VISUAL, "gN", "<vis-motion-byte-right>") -- gL
    vis:map(vis.modes.VISUAL, "gL", "<vis-textobject-search-backward>") -- gN
    vis:map(vis.modes.VISUAL, "gd", "<vis-motion-codepoint-prev>") -- gh
    vis:map(vis.modes.VISUAL, "gh", "<vis-motion-screenline-down>") -- gj
    vis:map(vis.modes.VISUAL, "gt", "<vis-motion-screenline-up>") -- gk
    vis:map(vis.modes.VISUAL, "gn", "<vis-motion-codepoint-next>") -- gl
    vis:map(vis.modes.VISUAL, "gl", "<vis-textobject-search-forward>") -- gn
    vis:map(vis.modes.VISUAL, "j", "vis-motion-till-line-right") -- t
    vis:map(vis.modes.VISUAL, "J", "vis-motion-till-line-left") -- T

    vis:map(vis.modes.INSERT, "<C-d>", "<Backspace>") -- <C-h>
    vis:map(vis.modes.INSERT, "<C-h>", "<vis-insert-verbatim>u000a") -- <C-j>
    vis:map(vis.modes.INSERT, "<C-t>", function(keys) 
        if #keys < 2 then
            return -1 -- need more input
        end
        local file = io.popen(string.format("vis-digraph '%s' 2>&1", keys:gsub("'", "'\\''")))
        local output = file:read('*all')
        local success, msg, status = file:close()
        if success then
            if vis.mode == vis.modes.INSERT then
                vis:insert(output)
            elseif vis.mode == vis.modes.REPLACE then
                vis:replace(output)
            end
        elseif msg == 'exit' then
            if status == 2 then
                return -1 -- prefix need more input
            end
            vis:info(output)
        end
        return #keys
    end, "Insert digraph") -- <C-k>
    vis:map(vis.modes.INSERT, "<C-k>", "<vis-operator-shift-left><vis-operator-shift-left>") -- <C-d>
    vis:map(vis.modes.INSERT, "<C-l>", function()
        local win = vis.win
        local file = win.file
        local pos = win.selection.pos
        if not pos then return end

        local range = file:text_object_word(pos > 0 and pos-1 or pos);
        if not range then return end
        if range.finish > pos then range.finish = pos end
        if range.start == range.finish then return end
        local prefix = file:content(range)
        if not prefix then return end

        vis:feedkeys("<vis-selections-save><Escape><Escape>")
        -- collect words starting with prefix
        vis:command("x/\\b" .. prefix .. "\\w+/")
        local candidates = {}
        for sel in win:selections_iterator() do
            table.insert(candidates, file:content(sel.range))
        end
        vis:feedkeys("<Escape><Escape><vis-selections-restore>")
        if #candidates == 1 and candidates[1] == "\n" then return end
        candidates = table.concat(candidates, "\n")

        local cmd = "printf '" .. candidates .. "' | sort -u | vis-menu"
        local status, out, err = vis:pipe(cmd)
        if status ~= 0 or not out then
            if err then vis:info(err) end
            return
        end
        out = out:sub(#prefix + 1, #out - 1)
        file:insert(pos, out)
        win.selection.pos = pos + #out
        -- restore mode to what it was on entry
        vis.mode = vis.modes.INSERT
    end, "Complete word in file") -- <C-n>
    vis:map(vis.modes.INSERT, "<C-j>", "<vis-operator-shift-right><vis-operator-shift-right>") -- <C-t>
end)

-- ...
VehementHam commented 2 months ago

BTW Michael Forney uses Dvorak.

mcepl commented 2 months ago

This very much looks like the best candidate for a separate plugin you would manage. The beauty of vis is that it is so simple to create new plugins in Lua and then just to keep them around.

VehementHam commented 2 months ago

Good idea. I might make a plugin. Sounds like a lot better of an idea than adding to the wiki

VehementHam commented 2 months ago

Still having issues with adding a description. I add a third argument, a string, as the description, but it doesn't display on the :help file.

VehementHam commented 2 months ago

I guess that this constitutes a plugin.

Of course, I will make a git repo for it and whatnot after I resolve description issue, and return the respective descriptions.

require("vis")

vis.events.subscribe(vis.events.INIT, function()
    -- key unmapppings
    vis:unmap(vis.modes.NORMAL, "<M-C-j>")
    vis:unmap(vis.modes.NORMAL, "<M-C-k")
    vis:unmap(vis.modes.NORMAL, "<C-w>j")
    vis:unmap(vis.modes.NORMAL, "gj")
    vis:unmap(vis.modes.NORMAL, "gJ")

    vis:unmap(vis.modes.OPERATOR_PENDING, "j")
    vis:unmap(vis.modes.OPERATOR_PENDING, "il")
    vis:unmap(vis.modes.OPERATOR_PENDING, "al")
    vis:unmap(vis.modes.OPERATOR_PENDING, "gj")

    vis:unmap(vis.modes.VISUAL, "<C-j>")
    vis:unmap(vis.modes.VISUAL, "il")
    vis:unmap(vis.modes.VISUAL, "al")
    vis:unmap(vis.modes.VISUAL, "gj")
    vis:unmap(vis.modes.NORMAL, "gJ")

    -- key mappings -- followed by bind it replaces
    vis:map(vis.modes.NORMAL, "d", "<vis-motion-char-prev>") -- h
    vis:map(vis.modes.NORMAL, "h", "<vis-motion-line-down>") -- j
    vis:map(vis.modes.NORMAL, "t", "<vis-motion-line-up>") -- k
    vis:map(vis.modes.NORMAL, "n", "<vis-motion-char-next>") -- l
    vis:map(vis.modes.NORMAL, "D", "<vis-motion-window-line-top>") -- H
    vis:map(vis.modes.NORMAL, "H", "<vis-join-lines>") -- J
    vis:map(vis.modes.NORMAL, "N", "<vis-motion-window-line-bottom>") -- L
    vis:map(vis.modes.NORMAL, "l", "<vis-motion-search-repeat>") -- n
    vis:map(vis.modes.NORMAL, "L", "<vis-motion-search-repeat-backward>") -- N
    vis:map(vis.modes.NORMAL, "k", "<vis-operator-delete>") -- d
    vis:map(vis.modes.NORMAL, "K", "k$") -- D, d$
    vis:map(vis.modes.NORMAL, "<M-C-h>", "<vis-new-selection-lines-below-last>") -- <M-C-j>
    vis:map(vis.modes.NORMAL, "<M-C-t>", "<vis-new-selection-lines-above-first>") -- <M-C-k>
    vis:map(vis.modes.NORMAL, "<C-w>d", "<C-w>t") -- <C-w>h, <C-w>k
    vis:map(vis.modes.NORMAL, "<C-w>h", "<vis-window-next>") -- <C-w>j
    vis:map(vis.modes.NORMAL, "<C-w>t", "<vis-window-prev>") -- <C-w>k
    vis:map(vis.modes.NORMAL, "<C-w>n", "<C-w>h") -- <C-w>l, <C-w>j
    vis:map(vis.modes.NORMAL, "<C-w>l", ":open<Enter>") -- <C-w>n
    vis:map(vis.modes.NORMAL, "<C-h>", "<new-selection-lines-below>") -- <C-j>
    vis:map(vis.modes.NORMAL, "<C-t>", "<new-selection-lines-above>") -- <C-k>
    vis:map(vis.modes.NORMAL, "<C-n>", "<vis-selections-remove-column-except>") -- <C-l>
    vis:map(vis.modes.NORMAL, "<C-k>", "<vis-selection-next>") -- <C-d>
    vis:map(vis.modes.NORMAL, "<C-l>", "viw") -- <C-n>
    vis:map(vis.modes.NORMAL, "+", "h^") -- +, j^
    vis:map(vis.modes.NORMAL, "-", "t^") -- -, k^
    vis:map(vis.modes.NORMAL, "X", "kd") -- X, dh
    vis:map(vis.modes.NORMAL, "s", "cn") -- s, cl
    vis:map(vis.modes.NORMAL, "gD", "<vis-motion-byte-left>") -- gH
    vis:map(vis.modes.NORMAL, "gH", "<vis-join-lines-trim>") -- gJ
    vis:map(vis.modes.NORMAL, "gN", "<vis-motion-byte-right>") -- gL
    vis:map(vis.modes.NORMAL, "gL", "vgL") -- gN, vgN
    vis:map(vis.modes.NORMAL, "gd", "<vis-motion-codepoint-prev>") -- gh
    vis:map(vis.modes.NORMAL, "gh", "<vis-motion-screenline-down>") -- gj
    vis:map(vis.modes.NORMAL, "gt", "<vis-motion-screenline-up>") -- gk
    vis:map(vis.modes.NORMAL, "gn", "<vis-motion-codepoint-next>") -- gl
    vis:map(vis.modes.NORMAL, "gl", "vgl") -- gn, vgn
    vis:map(vis.modes.NORMAL, "j", "vis-motion-till-line-right") -- t
    vis:map(vis.modes.NORMAL, "J", "vis-motion-till-line-left") -- T

    vis:map(vis.modes.OPERATOR_PENDING, "k", "<vis-operator-delete>") -- d
    vis:map(vis.modes.OPERATOR_PENDING, "d", "<vis-motion-char-prev>") -- h
    vis:map(vis.modes.OPERATOR_PENDING, "h", "<vis-motion-line-down>") -- j
    vis:map(vis.modes.OPERATOR_PENDING, "t", "<vis-motion-line-up>") -- k
    vis:map(vis.modes.OPERATOR_PENDING, "n", "<vis-motion-char-next>")  -- l
    vis:map(vis.modes.OPERATOR_PENDING, "D", "<vis-motion-window-line-top>") -- H
    vis:map(vis.modes.OPERATOR_PENDING, "N", "<vis-motion-window-line-bottom>") -- L
    vis:map(vis.modes.OPERATOR_PENDING, "l", "<vis-motion-search-repeat>") -- n
    vis:map(vis.modes.OPERATOR_PENDING, "L", "<vis-motion-search-repeat-backward>") -- N
    vis:map(vis.modes.OPERATOR_PENDING, "in", "<vis-textobject-line-inner>") -- il
    vis:map(vis.modes.OPERATOR_PENDING, "an", "<vis-textobject-line-outer>") -- al
    vis:map(vis.modes.OPERATOR_PENDING, "+", "h^") -- +, j^
    vis:map(vis.modes.OPERATOR_PENDING, "-", "t^") -- -, k^
    vis:map(vis.modes.OPERATOR_PENDING, "gD", "<vis-motion-byte-left>") -- gH
    vis:map(vis.modes.OPERATOR_PENDING, "gN", "<vis-motion-byte-right>") -- gL
    vis:map(vis.modes.OPERATOR_PENDING, "gL", "<vis-textobject-search-backward>") -- gN
    vis:map(vis.modes.OPERATOR_PENDING, "gd", "<vis-motion-codepoint-prev>") -- gh
    vis:map(vis.modes.OPERATOR_PENDING, "gh", "<vis-motion-screenline-down>") -- gj
    vis:map(vis.modes.OPERATOR_PENDING, "gt", "<vis-motion-screenline-up>") -- gk
    vis:map(vis.modes.OPERATOR_PENDING, "gn", "<vis-motion-codepoint-next>") -- gl
    vis:map(vis.modes.OPERATOR_PENDING, "gl", "<vis-textobject-search-forward>") -- gn
    vis:map(vis.modes.OPERATOR_PENDING, "j", "vis-motion-till-line-right") -- t
    vis:map(vis.modes.OPERATOR_PENDING, "J", "vis-motion-till-line-left") -- T

    vis:map(vis.modes.VISUAL, "d", "<vis-motion-char-prev>") -- h
    vis:map(vis.modes.VISUAL, "h", "<vis-motion-line-down>") -- j
    vis:map(vis.modes.VISUAL, "t", "<vis-motion-line-up>") -- k
    vis:map(vis.modes.VISUAL, "n", "<vis-motion-char-next>") -- l
    vis:map(vis.modes.VISUAL, "D", "<vis-motion-window-line-top>") -- H
    vis:map(vis.modes.VISUAL, "H", "<vis-join-lines>") -- J
    vis:map(vis.modes.VISUAL, "N", "<vis-motion-window-line-bottom>") -- L
    vis:map(vis.modes.VISUAL, "l", "<vis-motion-search-repeat>") -- n
    vis:map(vis.modes.VISUAL, "L", "<vis-motion-search-repeat-backward>") -- N
    vis:map(vis.modes.VISUAL, "k", "<vis-operator-delete>") -- d
    vis:map(vis.modes.VISUAL, "<C-h>", "<C-k>") -- <C-j>, <C-d>
    vis:map(vis.modes.VISUAL, "<C-t>", "<C-u>") -- <C-k>
    vis:map(vis.modes.VISUAL, "<C-n>", "<vis-selections-remove-column-except>") -- <C-l>
    vis:map(vis.modes.VISUAL, "<C-l>", "<vis-selection-new-match-next>") -- <C-n>
    vis:map(vis.modes.VISUAL, "<C-k>", "<vis-selection-next>") -- <C-d>
    vis:map(vis.modes.VISUAL, "in", "<vis-textobject-line-inner>") -- il
    vis:map(vis.modes.VISUAL, "an", "<vis-textobject-line-outer>") -- al
    vis:map(vis.modes.VISUAL, "x", "k") -- x, d
    vis:map(vis.modes.VISUAL, "gD", "<vis-motion-byte-left>") -- gH
    vis:map(vis.modes.VISUAL, "gH", "<vis-join-lines-trim>") -- gJ
    vis:map(vis.modes.VISUAL, "gN", "<vis-motion-byte-right>") -- gL
    vis:map(vis.modes.VISUAL, "gL", "<vis-textobject-search-backward>") -- gN
    vis:map(vis.modes.VISUAL, "gd", "<vis-motion-codepoint-prev>") -- gh
    vis:map(vis.modes.VISUAL, "gh", "<vis-motion-screenline-down>") -- gj
    vis:map(vis.modes.VISUAL, "gt", "<vis-motion-screenline-up>") -- gk
    vis:map(vis.modes.VISUAL, "gn", "<vis-motion-codepoint-next>") -- gl
    vis:map(vis.modes.VISUAL, "gl", "<vis-textobject-search-forward>") -- gn
    vis:map(vis.modes.VISUAL, "j", "vis-motion-till-line-right") -- t
    vis:map(vis.modes.VISUAL, "J", "vis-motion-till-line-left") -- T

    vis:map(vis.modes.INSERT, "<C-d>", "<Backspace>") -- <C-h>
    vis:map(vis.modes.INSERT, "<C-h>", "<vis-insert-verbatim>u000a") -- <C-j>
    vis:map(vis.modes.INSERT, "<C-t>", function(keys) 
        if #keys < 2 then
            return -1 -- need more input
        end
        local file = io.popen(string.format("vis-digraph '%s' 2>&1", keys:gsub("'", "'\\''")))
        local output = file:read('*all')
        local success, msg, status = file:close()
        if success then
            if vis.mode == vis.modes.INSERT then
                vis:insert(output)
            elseif vis.mode == vis.modes.REPLACE then
                vis:replace(output)
            end
        elseif msg == 'exit' then
            if status == 2 then
                return -1 -- prefix need more input
            end
            vis:info(output)
        end
        return #keys
    end, "Insert digraph") -- <C-k>
    vis:map(vis.modes.INSERT, "<C-k>", "<vis-operator-shift-left><vis-operator-shift-left>") -- <C-d>
    vis:map(vis.modes.INSERT, "<C-l>", function()
        local win = vis.win
        local file = win.file
        local pos = win.selection.pos
        if not pos then return end

        local range = file:text_object_word(pos > 0 and pos-1 or pos);
        if not range then return end
        if range.finish > pos then range.finish = pos end
        if range.start == range.finish then return end
        local prefix = file:content(range)
        if not prefix then return end

        vis:feedkeys("<vis-selections-save><Escape><Escape>")
        -- collect words starting with prefix
        vis:command("x/\\b" .. prefix .. "\\w+/")
        local candidates = {}
        for sel in win:selections_iterator() do
            table.insert(candidates, file:content(sel.range))
        end
        vis:feedkeys("<Escape><Escape><vis-selections-restore>")
        if #candidates == 1 and candidates[1] == "\n" then return end
        candidates = table.concat(candidates, "\n")

        local cmd = "printf '" .. candidates .. "' | sort -u | vis-menu"
        local status, out, err = vis:pipe(cmd)
        if status ~= 0 or not out then
            if err then vis:info(err) end
            return
        end
        out = out:sub(#prefix + 1, #out - 1)
        file:insert(pos, out)
        win.selection.pos = pos + #out
        -- restore mode to what it was on entry
        vis.mode = vis.modes.INSERT
    end, "Complete word in file") -- <C-n>
    vis:map(vis.modes.INSERT, "<C-j>", "<vis-operator-shift-right><vis-operator-shift-right>") -- <C-t>
end)
pippi1otta commented 2 months ago

Still having issues with adding a description. I add a third argument, a string, as the description, but it doesn't display on the :help file. ~@VehementHam

https://martanne.github.io/vis/doc/#Vis:map

You are using the third signature of Vis:map:

Vis:map(mode, key, alias)

It doesn't accept a help argument. Only the first one does:

Vis:map(mode, key, func[, help])

rnpnr commented 2 months ago

It doesn't accept a help argument. Only the first one does:

Heres a little function I have used in the past to help with that case:

-- returns a function that when called runs vis:feedkeys(keys)
local fk = function(keys)
    return function ()
        vis:feedkeys(keys)
    end
end

vis:map(vis.modes.NORMAL, "d", fk("<vis-motion-char-prev>"), "Help Text")

I'm not sure there is a good way of doing the help text though without just copying all of it directly. You could distribute a dvorak config.h instead which wouldn't require the copying.

VehementHam commented 2 months ago

I might make a seperate config.h in addition to the plugin.

Just wondering, how come you do this?

fk("<vis-motion-char-prev>")

What is the purpose of the fk()?

rnpnr commented 2 months ago

What is the purpose of the fk()?

It's mostly a style thing. You could define the function inline:

vis:map(vis.modes.NORMAL, "d", function() vis:feedkeys("<vis-motion-char-prev>") end, "Help Text")

But that I find that very ugly if you aren't doing anything else in the body. You can't put vis:feedkeys there directly as it will get called when vis:map gets called and not do what you want.

VehementHam commented 1 month ago

I see why, because you have to map to a function (in order to make use of the help text argument).