~glacambre/firenvim

eca09fa8c73a947934c2d71ea8fb944c71db8932 — glacambre 2 years ago 501a248
Add tslint-sonarts, fix lots of errors it detected, fix proxy
M package.json => package.json +2 -1
@@ 7,13 7,14 @@
    "awesome-typescript-loader": "^5.2.1",
    "copy-webpack-plugin": "^5.0.0",
    "tslint": "^5.13.1",
    "tslint-sonarts": "^1.9.0",
    "typescript": "^3.3.3333",
    "web-ext": "^3.0.0",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3"
  },
  "scripts": {
    "build": "cargo build --release && tslint --fix --project . && webpack && cargo run --release",
    "build": "tslint --fix --project . && webpack && cargo build --release && cargo run --release",
    "clean": "rm -rf target"
  },
  "author": "glacambre",

M src/Grid.ts => src/Grid.ts +0 -1
@@ 64,7 64,6 @@ export class Grid {
            this.rows = this.rows.slice(0, top)
                .concat(newRows)
                .concat(this.rows.slice(top, this.rows.length - newRows.length));
            rowCount = -rowCount;
        }
        this.cursor_goto(this.cursor.x, this.cursor.y);
    }

M src/Neovim.ts => src/Neovim.ts +1 -1
@@ 62,7 62,7 @@ export async function neovim(element: HTMLPreElement, selector: string) {
        }
    });

    const { 0: channel, 1: apiInfo } = (await request("nvim_get_api_info", [])) as INvimApiInfo;
    const { 1: apiInfo } = (await request("nvim_get_api_info", [])) as INvimApiInfo;
    return apiInfo.functions
        .filter(f => f.deprecated_since === undefined)
        .reduce((acc, cur) => {

M src/Redraw.ts => src/Redraw.ts +84 -103
@@ 8,111 8,92 @@ const cursorStyles: string[] = [];
const nvimCursorStyle = document.getElementById("nvim_cursor_style");
const nvimHighlightStyle = document.getElementById("nvim_highlight_style");

const redrawFuncs = {
    default_colors_set: (elem: HTMLElement, [fg, bg, sp, _, __]: [number, number, number, number, number]) => {
        if (fg !== undefined && fg !== -1) {
            defaultColors.foreground = fg;
            highlights[0].foreground = toHexCss(defaultColors.foreground);
        }
        if (bg !== undefined && bg !== -1) {
            defaultColors.background = bg;
            highlights[0].background = toHexCss(defaultColors.background);
        }
        nvimHighlightStyle.innerText = toCss(highlights);
    },
    flush: (elem: HTMLElement) => nvimHighlightStyle.innerText = toCss(highlights),
    grid_clear: (elem: HTMLElement, [id]: [number]) => grids[id].clear(),
    grid_cursor_goto: (elem: HTMLElement, [id, y, x]: GotoUpdate) => grids[id].cursor_goto(x, y),
    grid_line: (elem: HTMLElement, [id, row, col, contents]: LineUpdate) =>
    contents.reduce(({ prevCol, highlight }, content) => {
        const [chara, high = highlight, repeat = 1] = content;
        const limit = prevCol + repeat;
        for (let i = prevCol; i < limit; i += 1) {
            grids[id].get(row).get(i).value = chara;
            grids[id].get(row).get(i).highlight = high;
        }
        return { prevCol: limit, highlight: high };
    }, { prevCol: col, highlight: 0 }),
    grid_resize: (elem: HTMLElement, resize: ResizeUpdate) => {
        const [id, width, height] = resize;
        if (grids[id]) {
            grids[id].detach();
        }
        grids[id] = new Grid(width, height);
        grids[id].attach(elem);
    },
    grid_scroll: (elem: HTMLElement, [id, ...rest]: [number, number, number, number, number, number, number]) => {
        grids[id].scroll(...rest);
    },
    hl_attr_define: (elem: HTMLElement, [id, { foreground, background }]: HighlightUpdate) => {
        if (highlights[id] === undefined) {
            highlights[id] = { background: undefined, foreground: undefined };
        }
        highlights[id].foreground = foreground ? toHexCss(foreground) : undefined;
        highlights[id].background = background ? toHexCss(background) : undefined;
    },
    mode_change: (elem: HTMLElement, [modename, modeid]: [string, number]) => {
        const modePrefix = "nvim_mode_";
        Array.prototype.filter
            .call(elem.classList, (cname: string) => cname.startsWith(modePrefix))
            .forEach((cname: string) => elem.classList.remove(cname));
        elem.classList.add(modePrefix + modename);
        nvimCursorStyle.innerText = cursorStyles[modeid];
    },
    mode_info_set: (elem: HTMLElement, [cursorStyleEnabled, modeInfo]: [boolean, any]) => {
        if (cursorStyleEnabled) {
            modeInfo.forEach((info: any, idx: number) => {
                const { cursor_shape: shape } = info;
                let cssStr = `html body span.nvim_cursor { `;
                switch (shape) {
                    case "vertical":
                        cssStr += `box-sizing: border-box;`;
                        cssStr += `border-left: solid 1px ${highlights[0].foreground};`;
                        break;
                    case "horizontal":
                        cssStr += `box-sizing: border-box;`;
                        cssStr += `border-bottom: solid 1px ${highlights[0].foreground};`;
                        break;
                    case "block":
                        cssStr += `background: ${highlights[0].foreground};`;
                        cssStr += `color: ${highlights[0].background};`;
                        break;
                    default:
                        console.log(`Unhandled cursor shape: ${shape}`);
                }
                cssStr += "}";
                cursorStyles[idx] = cssStr;
            });
        }
    },
};

export function onRedraw(events: any[], elem: HTMLPreElement) {
    events.forEach(evt => {
        const [name, ...evts] = evt;
        switch (name) {
            case "default_colors_set":
                const [] = evts;
                evts.forEach(([fg, bg, sp, _, __]: [number, number, number, number, number]) => {
                    if (fg !== undefined && fg !== -1) {
                        defaultColors.foreground = fg;
                        highlights[0].foreground = toHexCss(defaultColors.foreground);
                    }
                    if (bg !== undefined && bg !== -1) {
                        defaultColors.background = bg;
                        highlights[0].background = toHexCss(defaultColors.background);
                    }
                });
                nvimHighlightStyle.innerText = toCss(highlights);
                break;
            case "hl_attr_define":
                evts.forEach(([id, { foreground, background }]: HighlightUpdate) => {
                    if (highlights[id] === undefined) {
                        highlights[id] = { background: undefined, foreground: undefined };
                    }
                    highlights[id].foreground = foreground ? toHexCss(foreground) : undefined;
                    highlights[id].background = background ? toHexCss(background) : undefined;
                });
                break;
            case "grid_clear":
                evts.forEach(([id]: [number]) => grids[id].clear());
                break;
            case "grid_cursor_goto":
                evts.forEach(([id, x, y]: GotoUpdate) => grids[id].cursor_goto(y, x) );
                break;
            case "grid_line":
                evts.forEach(([id, row, col, contents]: LineUpdate) =>
                    contents.reduce(({ prevCol, highlight }, content) => {
                        const [chara, high = highlight, repeat = 1] = content;
                        const limit = prevCol + repeat;
                        for (let i = prevCol; i < limit; i += 1) {
                            grids[id].get(row).get(i).value = chara;
                            grids[id].get(row).get(i).highlight = high;
                        }
                        return { prevCol: limit, highlight: high };
                    }, { prevCol: col, highlight: 0 }));
                break;
            case "grid_resize":
                evts.forEach((resize: ResizeUpdate) => {
                    const [id, width, height] = resize;
                    if (grids[id]) {
                        grids[id].detach();
                    }
                    grids[id] = new Grid(width, height);
                    grids[id].attach(elem);
                });
                break;
            case "grid_scroll":
                evts.forEach(([id, ...rest]: [number, number, number, number, number, number, number]) => {
                    grids[id].scroll(...rest);
                });
                break;
            case "mode_change":
                evts.forEach(([modename, modeid]: [string, number]) => {
                    const modePrefix = "nvim_mode_";
                    Array.prototype.filter
                        .call(elem.classList, (cname: string) => cname.startsWith(modePrefix))
                        .forEach((cname: string) => elem.classList.remove(cname));
                    elem.classList.add(modePrefix + modename);
                    nvimCursorStyle.innerText = cursorStyles[modeid];
                });
                break;
            case "mode_info_set":
                evts.forEach(([cursorStyleEnabled, modeInfo]: [boolean, any]) => {
                    if (cursorStyleEnabled) {
                        modeInfo.forEach((info: any, idx: number) => {
                            const { cursor_shape: shape, attr_id: attrId } = info;
                            let cssStr = `html body span.nvim_cursor { `;
                            switch (shape) {
                                case "vertical":
                                    cssStr += `box-sizing: border-box;`;
                                    cssStr += `border-left: solid 1px ${highlights[0].foreground};`;
                                    break;
                                case "horizontal":
                                    cssStr += `box-sizing: border-box;`;
                                    cssStr += `border-bottom: solid 1px ${highlights[0].foreground};`;
                                    break;
                                case "block":
                                    cssStr += `background: ${highlights[0].foreground};`;
                                    cssStr += `color: ${highlights[0].background};`;
                                    break;
                                default:
                                    console.log(`Unhandled cursor shape: ${shape}`);
                                    break;
                            }
                            cssStr += "}";
                            cursorStyles[idx] = cssStr;
                        });
                    }
                });
                break;
            case "flush":
                nvimHighlightStyle.innerText = toCss(highlights);
                break;
            default:
                console.log("Unhandled redraw request:", evt);
                break;
        const [name, ...evts]: [keyof typeof redrawFuncs, any] = evt;
        if (redrawFuncs[name] !== undefined) {
            evts.forEach((args) => redrawFuncs[name](elem, args));
        } else {
            console.log(`Unhandled redraw event: ${name}.`);
        }
    });
}

M src/Stdin.ts => src/Stdin.ts +0 -1
@@ 10,7 10,6 @@ export class Stdin {
    public write(reqId: number, method: string, args: any[]) {
        const req = [0, reqId, method, args];
        const encoded = msgpack.encode(req);
        // console.log("writing ", req, "encoded: ", encoded);
        this.port.postMessage({ type: "Buffer", data: Array.from(encoded)});
    }


M src/content.ts => src/content.ts +2 -3
@@ 5,16 5,15 @@ const global = {
    lastEditorLocation: ["", ""] as [string, string],
    nvimify: (evt: FocusEvent) => {
        const elem = evt.target as HTMLElement;
        const selector = computeSelector(elem as HTMLElement);
        const selector = computeSelector(elem);

        if (global.selectorToElems.get(selector) !== undefined) {
            return;
        }

        global.lastEditorLocation = [document.location.href, selector];
        const span = elem.ownerDocument
            .createElementNS("http://www.w3.org/1999/xhtml", "span") as HTMLSpanElement;

        global.lastEditorLocation = [document.location.href, selector];
        global.selectorToElems.set(selector, [span, elem]);

        const rect = elem.getBoundingClientRect();

M src/firenvim.d.ts => src/firenvim.d.ts +1 -2
@@ 38,5 38,4 @@ type ResizeUpdate = [number, number, number];
type GotoUpdate = [number, number, number];
type LineUpdate = [number, number, number, Array<[string, number, number?]>];

type HighlightArray = { foreground: string, background: string }[];

type HighlightArray = Array<{ foreground: string, background: string }>;

M src/page/functions.ts => src/page/functions.ts +4 -2
@@ 7,7 7,8 @@ export function getFunctions(global: {
    return {
        getEditorLocation: () => global.lastEditorLocation,
        getElementContent: (selector: string) => {
            const [_, e] = global.selectorToElems.get(selector) as [any, any];
            const [_ , e] = global.selectorToElems.get(selector) as [any, any];
            console.log(_);
            if (e.value !== undefined) {
                return e.value;
            }


@@ 28,7 29,8 @@ export function getFunctions(global: {
            }
        },
        setElementContent: (selector: string, text: string) => {
            const [_, e] = global.selectorToElems.get(selector) as [any, any];
            const [_ , e] = global.selectorToElems.get(selector) as [any, any];
            console.log(_);
            if (e.value !== undefined) {
                e.value = text;
            } else {

M src/page/proxy.ts => src/page/proxy.ts +7 -4
@@ 4,15 4,18 @@ import { getFunctions } from "./functions";
// get the name of functions that exist in the page.
const functions = getFunctions({} as any);

export const page = {} as typeof functions;
type ft = typeof functions;
type ArgumentsType<T> = T extends  (...args: infer U) => any ? U: never;

export const page = {} as { [k in keyof ft]: (...args: ArgumentsType<ft[k]>) => Promise<ReturnType<ft[k]>> };

let funcName: keyof typeof functions;
for (funcName in functions) {
    if (!functions.hasOwnProperty(funcName)) { // Make tslint happy
        continue;
    }
    // We need this local variable because Typescript won't let us give type
    // annotations to variables declared on for(... in ...) loops
    // We need to declare func here because funcName is a global and would not
    // be captured in the closure otherwise
    const func = funcName;
    page[func] = ((...arr: any[]) => {
        return browser.runtime.sendMessage({


@@ 22,5 25,5 @@ for (funcName in functions) {
            },
            function: "messageOwnTab",
        });
    }) as ((typeof functions)[typeof func]);
    });
}

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