~glacambre/firenvim

8d90a8c3fa5f59a46a206f5fa94a9df7bbda4d8a — glacambre 2 years ago 1317fa8
Populate buffer with textarea content, remove iframe on VimLeave
4 files changed, 59 insertions(+), 17 deletions(-)

M src/Neovim.ts
M src/NeovimUi.ts
M src/content.ts
M tslint.json
M src/Neovim.ts => src/Neovim.ts +9 -0
@@ 56,6 56,15 @@ export async function neovim(element: HTMLPreElement, selector: string) {
                    function: "messageOwnTab",
                });
                break;
            case "firenvim_vimleave":
                browser.runtime.sendMessage({
                    args: {
                        args: [selector],
                        function: "killEditor",
                    },
                    function: "messageOwnTab",
                });
                break;
            default:
                console.log(`Unhandled notification '${name}':`, args);
                break;

M src/NeovimUi.ts => src/NeovimUi.ts +15 -3
@@ 70,6 70,13 @@ 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


@@ 88,9 95,14 @@ window.addEventListener("load", async () => {
        ext_linegrid: true,
        rgb: true,
    });
    nvim.command(`edit ${toFileName(url, selector)}`);
    nvim.command("autocmd BufWrite * "
        + "call rpcnotify(1, 'firenvim_bufwrite', {'text': nvim_buf_get_lines(0, 0, -1, 0)})");
    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;

M src/content.ts => src/content.ts +33 -13
@@ 1,5 1,34 @@
import { computeSelector } from "./CSSUtils";

const selectorToElems = new Map<string, [HTMLSpanElement, HTMLElement]>();

const functions: any = {
    getEditorLocation: () => lastEditorLocation,
    getElementContent: (selector: string) => {
        const [_, e] = selectorToElems.get(selector) as [any, any];
        if (e.value !== undefined) {
            return e.value;
        }
        if (e.textContent !== undefined) {
            return e.textContent;
        }
        return e.innerText;
    },
    killEditor: (selector: string) => {
        const [e, _] = selectorToElems.get(selector) as [any, any];
        e.parentNode.removeChild(e);
        selectorToElems.delete(selector);
    },
    setElementContent: (selector: string, text: string) => {
        const [_, e] = selectorToElems.get(selector) as [any, any];
        if (e.value !== undefined) {
            e.value = text;
        } else {
            e.textContent = text;
        }
    },
};

browser.runtime.onMessage.addListener(async (request: any, sender: any, sendResponse: any) => {
    if (!functions[request.function]) {
        throw new Error(`Error: unhandled content request: ${request.toString()}.`);


@@ 25,7 54,10 @@ function nvimify(evt: FocusEvent) {
    span.attachShadow({ mode: "closed" }).appendChild(iframe);
    elem.ownerDocument.body.appendChild(span);
    iframe.focus();
    lastEditorLocation = [document.location.href, computeSelector(evt.target as HTMLElement)];

    const selector = computeSelector(evt.target as HTMLElement);
    lastEditorLocation = [document.location.href, selector];
    selectorToElems.set(selector, [span, elem]);
}

function isEditable(elem: HTMLElement) {


@@ 33,18 65,6 @@ function isEditable(elem: HTMLElement) {
        || (elem.tagName === "INPUT" && (elem as HTMLInputElement).type === "text");
}

const functions: any = {
    getEditorLocation: () => lastEditorLocation,
    setElementContent: (selector: string, text: string) => {
        const e = document.querySelector(selector) as any;
        if (e.value) {
            e.value = text;
        } else {
            e.innerText = text;
        }
    },
};

(new MutationObserver(changes => {
    changes
        .filter((change: MutationRecord) => change.addedNodes.length > 0)

M tslint.json => tslint.json +2 -1
@@ 2,9 2,10 @@
  "extends": "tslint:recommended",
  "rules": {
    "arrow-parens": false,
    "no-conditional-assignment": false,
    "no-console": false,
    "no-namespace": false,
    "no-conditional-assignment": false,
    "no-switch-case-fall-through": true,
    "semicolon": [true, "always"]
  }
}