<commit_before>import {Session} from "../shell/Session";
import {SplitDirection} from "../Enums";
import {SessionComponent} from "../views/2_SessionComponent";
import * as _ from "lodash";

export type PaneTree = Pane | PaneList;

export class Pane {
    readonly session: Session;
    readonly size = 1;
    private _sessionComponent: SessionComponent;

    constructor(session: Session) {
        this.session = session;
    }

    setSessionComponent(component: SessionComponent) {
        this._sessionComponent = component;
    }

    sessionComponent(): SessionComponent {
        return this._sessionComponent;
    }
}

export abstract class PaneList {
    readonly children: PaneTree[];

    constructor(children: PaneTree[]) {
        this.children = children;
    }

    /**
     * Add a new pane after the existing one.
     */
    add(newPane: Pane, existingPane: Pane, direction: SplitDirection) {
        const list = this.findListWithDirectChild(existingPane);

        if (!list) {
            throw `Couldn't find a list containing the pane.`;
        }

        const insertIndex = list.children.indexOf(existingPane);

        if (direction === SplitDirection.Horizontal) {
            list.insertBelow(insertIndex, newPane);
        } else {
            list.insertNextTo(insertIndex, newPane);
        }
    }

    remove(pane: Pane) {
        const list = this.findListWithDirectChild(pane);

        if (!list) {
            throw `Couldn't find a list containing the pane.`;
        }

        list.children.splice(list.children.indexOf(pane), 1);
    }

    get size(): number {
        return _.sum(this.children.map(child => child.size));
    }

    forEach(callback: (pane: Pane, index: number) => void, counter = 0): void {
        for (const child of this.children) {
            if (child instanceof Pane) {
                callback(child, counter);
                ++counter;
            } else {
                child.forEach((pane) => {
                    callback(pane, counter);
                    ++counter;
                });
            }
        }
    }

    /**
     * Returns the pane previous to the 'pane' argument provided.
     * @param {Pane} pane The reference pane.
     * @returns {Pane}
     */
    previous(pane: Pane): Pane {
        const firstPaneIndex = 0;
        const lastPaneIndex = this.size - 1;
        let paneIndex = 0;

        this.forEach((current, index) => {
            if (pane === current) {
                paneIndex = index;
            }
        });

        let previous = pane;

        this.forEach((current, index) => {
            if (paneIndex === firstPaneIndex) {
                if (index === lastPaneIndex)
                    previous = current;
            } else if (index === paneIndex - 1) {
                previous = current;
            }
        });

        return previous;
    }

    /**
     * Returns the pane next after the 'pane' argument provided.
     * @param {Pane} pane The reference pane.
     * @returns {Pane}
     */
    next(pane: Pane): Pane {
        const firstPaneIndex = 0;
        const lastPaneIndex = this.size - 1;
        let paneIndex = 0;

        this.forEach((current, index) => {
            if (pane === current) {
                paneIndex = index;
            }
        });

        let next = pane;

        this.forEach((current, index) => {
            if (paneIndex === lastPaneIndex) {
                if (index === firstPaneIndex)
                    next = current;
            } else if (index === paneIndex + 1) {
                next = current;
            }
        });

        return next;
    }

    protected abstract insertBelow(position: number, pane: Pane): void;
    protected abstract insertNextTo(position: number, pane: Pane): void;

    private findListWithDirectChild(tree: PaneTree): PaneList | undefined {
        const childContaining = this.children.find(child => child === tree);

        if (childContaining) {
            return this;
        }

        for (const child of this.children) {
            if (child instanceof PaneList) {
                const childListContaining = child.findListWithDirectChild(tree);
                if (childListContaining) {
                    return childListContaining;
                }
            }
        }
    }
}

export class ColumnList extends PaneList {
    protected insertBelow(position: number, pane: Pane) {
        this.children.splice(position, 1, new RowList([this.children[position], pane]));
    }

    protected insertNextTo(position: number, pane: Pane) {
        this.children.splice(position + 1, 0, pane);
    }
}

export class RowList extends PaneList {
    protected insertBelow(position: number, pane: Pane) {
        this.children.splice(position + 1, 0, pane);
    }

    protected insertNextTo(position: number, pane: Pane) {
        this.children.splice(position, 1, new ColumnList([this.children[position], pane]));
    }
}
<commit_msg>Improved performance of PaneList next & previous methods (#1002)<commit_after>import {Session} from "../shell/Session";
import {SplitDirection} from "../Enums";
import {SessionComponent} from "../views/2_SessionComponent";
import * as _ from "lodash";

export type PaneTree = Pane | PaneList;

export class Pane {
    readonly session: Session;
    readonly size = 1;
    private _sessionComponent: SessionComponent;

    constructor(session: Session) {
        this.session = session;
    }

    setSessionComponent(component: SessionComponent) {
        this._sessionComponent = component;
    }

    sessionComponent(): SessionComponent {
        return this._sessionComponent;
    }
}

export abstract class PaneList {
    readonly children: PaneTree[];

    constructor(children: PaneTree[]) {
        this.children = children;
    }

    /**
     * Add a new pane after the existing one.
     */
    add(newPane: Pane, existingPane: Pane, direction: SplitDirection) {
        const list = this.findListWithDirectChild(existingPane);

        if (!list) {
            throw `Couldn't find a list containing the pane.`;
        }

        const insertIndex = list.children.indexOf(existingPane);

        if (direction === SplitDirection.Horizontal) {
            list.insertBelow(insertIndex, newPane);
        } else {
            list.insertNextTo(insertIndex, newPane);
        }
    }

    remove(pane: Pane) {
        const list = this.findListWithDirectChild(pane);

        if (!list) {
            throw `Couldn't find a list containing the pane.`;
        }

        list.children.splice(list.children.indexOf(pane), 1);
    }

    get size(): number {
        return _.sum(this.children.map(child => child.size));
    }

    forEach(callback: (pane: Pane, index: number) => void, counter = 0): void {
        for (const child of this.children) {
            if (child instanceof Pane) {
                callback(child, counter);
                ++counter;
            } else {
                child.forEach((pane) => {
                    callback(pane, counter);
                    ++counter;
                });
            }
        }
    }

    /**
     * Returns the pane previous to the 'pane' argument provided.
     * @param {Pane} pane The reference pane.
     * @returns {Pane}
     */
    previous(pane: Pane): Pane {
        let paneIndex = 0;
        let panes: Pane[] = [];

        this.forEach((currentPane, index) => {
            panes.push(currentPane);
            if (pane === currentPane) {
                paneIndex = index;
            }
        });

        if (paneIndex === 0) {
            return panes[panes.length - 1];
        } else {
            return panes[paneIndex - 1];
        }
    }

    /**
     * Returns the pane next after the 'pane' argument provided.
     * @param {Pane} pane The reference pane.
     * @returns {Pane}
     */
    next(pane: Pane): Pane {
        let paneIndex = 0;
        let panes: Pane[] = [];

        this.forEach((currentPane, index) => {
            panes.push(currentPane);
            if (pane === currentPane) {
                paneIndex = index;
            }
        });

        if (paneIndex === panes.length - 1) {
            return panes[0];
        } else {
            return panes[paneIndex + 1];
        }
    }

    protected abstract insertBelow(position: number, pane: Pane): void;
    protected abstract insertNextTo(position: number, pane: Pane): void;

    private findListWithDirectChild(tree: PaneTree): PaneList | undefined {
        const childContaining = this.children.find(child => child === tree);

        if (childContaining) {
            return this;
        }

        for (const child of this.children) {
            if (child instanceof PaneList) {
                const childListContaining = child.findListWithDirectChild(tree);
                if (childListContaining) {
                    return childListContaining;
                }
            }
        }
    }
}

export class ColumnList extends PaneList {
    protected insertBelow(position: number, pane: Pane) {
        this.children.splice(position, 1, new RowList([this.children[position], pane]));
    }

    protected insertNextTo(position: number, pane: Pane) {
        this.children.splice(position + 1, 0, pane);
    }
}

export class RowList extends PaneList {
    protected insertBelow(position: number, pane: Pane) {
        this.children.splice(position + 1, 0, pane);
    }

    protected insertNextTo(position: number, pane: Pane) {
        this.children.splice(position, 1, new ColumnList([this.children[position], pane]));
    }
}

{'fraction_non_alphanumeric': 0.11186334756796167, 'fraction_numerical': 0.004166232684095407, 'mean_word_length': 1.948111759287688, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4473676', 'n_tokens_mistral': 2780, 'n_tokens_neox': 2592, 'n_words': 683}