~glacambre/firenvim

ref: 8d90a8c3fa5f59a46a206f5fa94a9df7bbda4d8a firenvim/src/NeovimUi.ts -rw-r--r-- 3.8 KiB
8d90a8c3glacambre Populate buffer with textarea content, remove iframe on VimLeave 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { neovim } from "./Neovim";

function translateKey(text: string) {
    switch (text) {
        case " ":
            return "<Space>";
        case "ArrowDown":
            return "<Down>";
        case "ArrowLeft":
            return "<Left>";
        case "ArrowRight":
            return "<Right>";
        case "ArrowUp":
            return "<Up>";
        case "Backspace":
            return "<BS>";
        case "Delete":
            return "<Del>";
        case "End":
            return "<End>";
        case "Enter":
            return "<CR>";
        case "Escape":
            return "<Esc>";
        case "Home":
            return "<Home>";
        case "PageDown":
            return "<PageDown>";
        case "PageUp":
            return "<PageUp>";
        case "Tab":
            return "<Tab>";
        case "<":
            return "<lt>";
        case "\\":
            return "<Bslash>";
        case "|":
            return "<Bar>";
    }
    return text;
}

function addModifier(mod: string, text: string) {
    let match;
    let modifiers = "";
    let key = "";
    if ((match = text.match(/^<([A-Z]{1,5})-(.+)>$/))) {
        modifiers = match[1];
        key = match[2];
    } else if ((match = text.match(/^<(.+)>$/))) {
        key = match[1];
    } else {
        key = text;
    }
    return "<" + mod + modifiers + "-" + key + ">";
}

function toFileName(url: string, id: string) {
    const parsedURL = new URL(url);
    const toAlphaNum = (str: string) => (str.match(/[a-zA-Z0-9]+/g) || []).join("-");
    return `${parsedURL.hostname}_${toAlphaNum(parsedURL.pathname)}_${toAlphaNum(id)}.txt`;
}

const locationPromise = browser.runtime.sendMessage({
    args: {function: "getEditorLocation"},
    function: "messageOwnTab",
});

window.addEventListener("load", async () => {
    const host = document.getElementById("pre") as HTMLPreElement;
    const [url, selector] = await locationPromise;
    const nvimPromise = neovim(host, selector);
    const contentPromise = browser.runtime.sendMessage({
        args: {
            args: [selector],
            function: "getElementContent",
        },
        function: "messageOwnTab",
    });

    // We need to know how tall/wide our characters are in order to know how
    // many rows/cols we can have
    const span = document.createElement("span");
    span.innerText = " ";
    host.appendChild(span);
    const { width: charWidth, height: charHeight } = span.getBoundingClientRect();
    host.removeChild(span);
    const rect = host.getBoundingClientRect();
    const cols = Math.floor(rect.width / charWidth);
    const rows = Math.floor(rect.height / charHeight);

    const nvim = await nvimPromise;

    nvim.ui_attach(cols, rows, {
        ext_linegrid: true,
        rgb: true,
    });
    const filename = toFileName(url, selector);
    nvim.command(`edit ${filename}`)
        .then((_: any) => contentPromise
            .then(content =>
                nvim.buf_set_lines(0, 0, -1, 0, content.split("\n"))));
    nvim.command(`autocmd BufWrite ${filename} `
        + `call rpcnotify(1, 'firenvim_bufwrite', {'text': nvim_buf_get_lines(0, 0, -1, 0)})`);
    nvim.command("autocmd VimLeave * call rpcnotify(1, 'firenvim_vimleave')");
    window.addEventListener("keydown", (evt) => {
        if (evt.isTrusted && evt.key !== "OS" && evt.key !== "AltGraph") {
            const special = false;
            const text = [["altKey", "A"], ["ctrlKey", "C"], ["metaKey", "M"], ["shiftKey", "S"]]
                .reduce((key: string, [attr, mod]: [string, string]) => {
                    if ((evt as any)[attr]) {
                        return addModifier(mod, key);
                    }
                    return key;
                }, translateKey(evt.key));
            nvim.input(text);
            evt.preventDefault();
            evt.stopImmediatePropagation();
        }
    });
});