void UpdateScroll(Window *window, bool update_caret_scrolling) {
    ProfileFunction();
    BSet set = GetBSet(window);

    // Scrolling with caret
    if (update_caret_scrolling) {
        Caret c     = set.view->carets[0];
        Int   front = GetFront(c);
        XY    xy    = PosToXY(set.buffer, front);

        Rect2I visible       = GetVisibleCells(window);
        Vec2I  visible_cells = GetSize(visible);
        Vec2I  visible_size  = visible_cells * Vec2I{window->font->char_spacing, window->font->line_spacing};
        Vec2I  rect_size     = GetSize(window->document_rect);

        if (xy.line >= visible.max.y - 2) {
            Int set_view_at_line = xy.line - (visible_cells.y - 1);
            Int cut_off_y        = Max((Int)0, visible_size.y - rect_size.y);
            set.view->scroll.y   = (set_view_at_line * window->font->line_spacing) + cut_off_y;
        }

        if (xy.line < visible.min.y + 1) {
            set.view->scroll.y = xy.line * window->font->line_spacing;
        }

        if (xy.col >= visible.max.x - 1) {
            Int set_view_at_line = xy.col - (visible_cells.x - 1);
            Int cut_off_x        = Max((Int)0, visible_size.x - rect_size.x);
            set.view->scroll.x   = (set_view_at_line * window->font->char_spacing) + cut_off_x;
        }

        if (xy.col <= visible.min.x) {
            set.view->scroll.x = xy.col * window->font->char_spacing;
        }
    }

    // Clip scroll
    {
        Int last_line      = LastLine(set.buffer);
        set.view->scroll.y = Clamp(set.view->scroll.y, (Int)0, Max((Int)0, (last_line - 1) * window->font->line_spacing));

        // @note:
        // GetCharCountOfLongestLine is a bottleneck, there is probably an algorithm for
        // calculating this value incrementally but do we even need X scrollbar or x clipping?
        set.view->scroll.x = ClampBottom(set.view->scroll.x, (Int)0);
    }
}

void FuzzySearchOpen(BSet active) {
    bool success = false;
    Range range = active.view->carets[0].range;
    if (GetSize(range) == 0) {
        Int line = PosToLine(active.buffer, range.min);
        if ((active.buffer->line_starts.len - 1) == line) {
            line = ClampBottom(0ll, line - 1ll);
        }

        String16 string = GetLineStringWithoutNL(active.buffer, line);
        Int idx = 0;
        if (Seek(string, u"||", &idx)) {
            string = Skip(string, idx + 3);
            Open(string);
            success = true;
        }
    }

    if (!success) {
        Open(FetchLoadWord());
    }
}

void OnCommand(Event event) {
    ProfileFunction();
    //
    // Window cursor setting
    //
    Scratch    scratch;
    Array<Window *> order = GetWindowZOrder(scratch);


    // Handle wheel scrolling
    if (event.xwheel || event.ywheel) {
        Vec2I mouse = MouseVec2I();

        For(order) {
            if (!it->visible) continue;

            bool mouse_in_window = AreOverlapping(mouse, it->total_rect);
            if (mouse_in_window) {
                View *view = GetView(it->active_view);
                view->scroll.y -= (Int)(event.ywheel * 48);
                view->scroll.x += (Int)(event.xwheel * 48);
                break;
            }
        }
    }

    // Handle selected window scrollbar
    // @note: the order here assumes that we won't run this code on the
    // same event as the scroll was pressed
    if (IsScrollbarSelectionValid() && Mouse(LEFT_UP)) {
        Assert(DocumentSelected.id == -1);
        ScrollbarSelected.id = -1;
    } else if (IsScrollbarSelectionValid()) {
        // :ScrollbarImprovement
        // @todo: it generally works ok but it moves the scrollbar a bit on click
        // when mouse is not even moving
        Assert(DocumentSelected.id == -1);
        Window  *window     = GetWindow(ScrollbarSelected);
        View    *view       = GetView(window->active_view);
        Vec2     mouse_vec2 = MouseVec2();
        Scroller s          = ComputeScrollerRect(window);
        double   size_y     = (double)GetSize(window->scrollbar_rect).y;
        double   p          = mouse_vec2.y - window->scrollbar_rect.min.y;
        double   v          = p / size_y;
        v                   = v + (window->mouse_scroller_offset);
        view->scroll.y      = (Int)(v * (double)s.line_count * (double)window->font->line_spacing);
    }

    if (DocumentSelected != ActiveWindowID) {
        DocumentSelected.id = -1;
    } else if (IsDocumentSelectionValid() && MouseUp()) {
        Assert(ScrollbarSelected.id == -1);
        DocumentSelected.id = -1;
    } else if (IsDocumentSelectionValid()) {
        Assert(ScrollbarSelected.id == -1);
        BSet selected = GetBSet(DocumentSelected);


        Vec2I mouse = MouseVec2I();
        // Special case for full-screen where we can have document
        // aligned with monitor screen in which case mouse cursor cannot
        // be smaller then 0 which means we cannot scroll
        if (mouse.y == 0 && selected.window->document_rect.min.y == 0) {
            float x, y;
            SDL_GetGlobalMouseState(&x, &y);
            if (y == 0) {
                mouse.y = -10;
            }
        }

        Int    p     = ScreenSpaceToBufferPos(selected.window, selected.view, selected.buffer, mouse);
        Caret &caret = selected.view->carets[0];
        caret = SetFrontWithAnchor(caret, DocumentAnchor, p);
    }

    if (ResizerSelected.id != -1 && Mouse(LEFT_UP)) {
        Assert(DocumentSelected.id == -1);
        Assert(ScrollbarSelected.id == -1);
        ResizerSelected.id = {-1};
    } else if (ResizerSelected.id != -1) {
        Window *window = GetWindow(ResizerSelected);
        if (window->layout) {
            Vec2I mouse = MouseVec2I();
            Int offx = mouse.x - window->resizer_rect.min.x;
            window->weight += (double)offx / (double)WindowCalcEvenResizerValue(event.xwindow);
            window->weight = Clamp(window->weight, 0.1, 100.0);
        }
    } else {
        ResizerHover = {-1};
        For(Windows) {
            Vec2I mouse = MouseVec2I();
            bool mouse_in_rect = AreOverlapping(mouse, it->resizer_rect);
            if (mouse_in_rect) {
                ResizerHover = it->id;
                if (Mouse(LEFT)) {
                    ResizerSelected = it->id;
                }
            }
        }
    }

    // Set active window on click
    if (MousePress()) {
        Vec2I mouse = MouseVec2I();
        For(order) {
            if (!it->visible) {
                continue;
            }
            bool mouse_in_document = AreOverlapping(mouse, it->document_rect);
            if (mouse_in_document) {
                NextActiveWindowID = it->id;
                break;
            }
        }
    }

    if (Mouse(X2)) {
        BSet main = GetBSet(LastActiveLayoutWindowID);
        GotoForward(main.window);
    }
    if (Mouse(X1)) {
        BSet main = GetBSet(LastActiveLayoutWindowID);
        GotoBackward(main.window);
    }

    if (Ctrl() && Shift() && Mouse(RIGHT)) {

    } else if (Alt() && Ctrl() && Mouse(RIGHT)) {
    } else if (Ctrl() && Mouse(RIGHT)) {

    } else if (Alt() && Mouse(RIGHT)) {
    } else if (Mouse(RIGHT)) {
        Vec2I mouse = MouseVec2I();
        BSet  active = GetBSet(ActiveWindowID);
        bool  mouse_in_document = AreOverlapping(mouse, active.window->document_rect);
        if (mouse_in_document) {
            Int p           = ScreenSpaceToBufferPos(active.window, active.view, active.buffer, mouse);
            Int saved_front = -1;

            IterRemove(active.view->carets) {
                IterRemovePrepare(active.view->carets);
                if (InBounds(it.range, p)) {
                    String16 string = GetString(active.buffer, it.range);
                    SaveStringInClipboard(string);

                    remove_item = true;
                    saved_front = GetFront(it);
                }
            }
            if (active.view->carets.len == 0) Add(&active.view->carets, MakeCaret(saved_front));

            if (saved_front == -1) {
                Int      line       = PosToLine(active.buffer, p);
                Range    line_range = GetLineRangeWithoutNL(active.buffer, line);
                String16 string     = GetString(active.buffer, line_range);
                SaveStringInClipboard(string);
            }
        }
    }

    if (Ctrl() && Mouse(LEFT)) {
        MouseLoadWord(event);
    } else if (Mouse(LEFT)) { // Uses Alt and shift
        Vec2I mouse = MouseVec2I();
        {
            Assert(ScrollbarSelected.id == -1);
            Assert(DocumentSelected.id == -1);

            BSet active = GetBSet(NextActiveWindowID); // using next to make sure mouse works on first click after switching the window
            bool mouse_in_document     = AreOverlapping(mouse, active.window->document_rect);
            bool mouse_in_line_numbers = AreOverlapping(mouse, active.window->line_numbers_rect);
            if (mouse_in_document || mouse_in_line_numbers) {
                DocumentSelected = active.window->id;
                CheckpointBeforeGoto(active.window);


                Int p = ScreenSpaceToBufferPos(active.window, active.view, active.buffer, mouse);
                if (Alt()) Insert(&active.view->carets, MakeCaret(p, p), 0);
                if (!Alt() && !Shift()) active.view->carets.len = 1;

                Caret &caret = active.view->carets[0];
                if (Shift()) {
                    if (p <= caret.range.min) {
                        caret.range.min = p;
                        caret.ifront    = 0;
                    } else if (p >= caret.range.max) {
                        caret.range.max = p;
                        caret.ifront    = 1;
                    }
                } else if (event.clicks >= 2 && InBounds({caret.range.min - 1, caret.range.max + 1}, p)) {
                    Range range = EncloseWord(active.buffer, p);
                    if (event.clicks >= 3) {
                        range = EncloseFullLine(active.buffer, p);
                    }
                    caret = MakeCaret(range.max, range.min);
                } else {
                    caret = MakeCaret(p);
                }
                MergeCarets(active.buffer, &active.view->carets);
                DocumentAnchor = caret;
            }
        }

        // Figure out scrollbar click
        // :ScrollbarImprovement
        // @todo: it generally works ok but it moves the scrollbar a bit on click
        // when mouse is not even moving
        For(order) {
            if (!it->visible) continue;
            bool mouse_in_scrollbar = AreOverlapping(mouse, it->scrollbar_rect);
            if (mouse_in_scrollbar) {
                ScrollbarSelected = it->id;

                View    *view       = GetView(it->active_view);
                Vec2     mouse_vec2 = MouseVec2();
                Scroller s          = ComputeScrollerRect(it);
                double   size_y     = (double)GetSize(it->scrollbar_rect).y;
                double   p          = mouse_vec2.y - it->scrollbar_rect.min.y;
                if (mouse_vec2.y < s.rect.min.y || mouse_vec2.y > s.rect.max.y) {
                    view->scroll.y                = (Int)(p / size_y * (double)s.line_count * (double)it->font->line_spacing);
                    it->mouse_scroller_offset = -(double)GetSize(s.rect).y / 2.0 / size_y;
                } else {
                    it->mouse_scroller_offset = (s.rect.min.y - p) / size_y;
                }
                break;
            }
        }
    }

    if (CtrlPress(SDLK_W)) {
        Command_KillWindow();
    }

    if (CtrlAltPress(SDLK_P)) {
    } else if (CtrlShiftPress(SDLK_P)) {
        Command_ShowCommandList();
    } else if (CtrlPress(SDLK_P)) {
        Command_ShowBufferList();
    }

    if (CtrlPress(SDLK_0)) {
        Command_ToggleDebug();
    }

    if (CtrlPress(SDLK_1)) {
        NextActiveWindowID = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID))->id;
    }
    if (CtrlPress(SDLK_2)) {
        Window *first = GetOverlappingWindow({0,0}, GetWindow(ActiveWindowID));
        Vec2I p = GetSideOfWindow(first, DIR_RIGHT);
        NextActiveWindowID = GetOverlappingWindow(p, GetWindow(ActiveWindowID))->id;
    }
    if (CtrlPress(SDLK_3)) {
        Window *first = GetOverlappingWindow({0,0});
        if (first) {
            Window *second = GetOverlappingWindow(GetSideOfWindow(first, DIR_RIGHT));
            if (second) {
                Window *third = GetOverlappingWindow(GetSideOfWindow(second, DIR_RIGHT));
                if (third) {
                    NextActiveWindowID = third->id;
                }
            }
        }
    }

    BSet main = GetBSet(LastActiveLayoutWindowID);
    BSet active = GetBSet(ActiveWindowID);
    Int  buffer_change_id = active.buffer->change_id;

    bool skip = CallOnCommand(&event);
    if (skip) {
        // :OnCommandEnding
        MergeCarets(active.buffer, &active.view->carets);
        IF_DEBUG(AssertRanges(active.view->carets));
        return;
    }

    if (active.view->fuzzy_search) {
        if (Press(SDLK_RETURN)) {
            FuzzySearchOpen(active);
            return;
        }
    }

    if (event.kind == EVENT_DROP_FILE) {
        WindowOpenBufferView(active.window, event.text);
    }

    if (Press(SDLK_DOWN) || Press(SDLK_RIGHT) || Press(SDLK_LEFT) || Press(SDLK_UP)) {
        CheckpointBeforeGoto(active.window);
    }

    if (CtrlAltPress(SDLK_DOWN)) {
        DuplicateLine(active.view, DIR_DOWN);
    } else if (AltShiftPress(SDLK_DOWN)) {
        CreateCursorVertical(active.view, DIR_DOWN);
    } else if (CtrlShiftPress(SDLK_DOWN)) {
        MoveCarets(active.view, DIR_DOWN, CTRL_PRESSED, SHIFT_PRESS);
    } else if (AltPress(SDLK_DOWN)) {
        MoveCaretsLine(active.view, DIR_DOWN);
    } else if (CtrlPress(SDLK_DOWN)) {
        MoveCarets(active.view, DIR_DOWN, CTRL_PRESSED);
    } else if (ShiftPress(SDLK_DOWN)) {
        MoveCarets(active.view, DIR_DOWN, false, SHIFT_PRESS);
    } else if (Press(SDLK_DOWN)) {
        MoveCarets(active.view, DIR_DOWN);
    }

    if (CtrlAltPress(SDLK_UP)) {
        DuplicateLine(active.view, DIR_UP);
    } else if (AltShiftPress(SDLK_UP)) {
        CreateCursorVertical(active.view, DIR_UP);
    } else if (CtrlShiftPress(SDLK_UP)) {
        MoveCarets(active.view, DIR_UP, CTRL_PRESSED, SHIFT_PRESS);
    } else if (AltPress(SDLK_UP)) {
        MoveCaretsLine(active.view, DIR_UP);
    } else if (CtrlPress(SDLK_UP)) {
        MoveCarets(active.view, DIR_UP, CTRL_PRESSED);
    } else if (ShiftPress(SDLK_UP)) {
        MoveCarets(active.view, DIR_UP, false, SHIFT_PRESS);
    } else if (Press(SDLK_UP)) {
        MoveCarets(active.view, DIR_UP);
    }

    if (CtrlShiftPress(SDLK_LEFT)) {
        MoveCarets(active.view, DIR_LEFT, CTRL_PRESSED, SHIFT_PRESS);
    } else if (CtrlPress(SDLK_LEFT)) {
        MoveCarets(active.view, DIR_LEFT, CTRL_PRESSED);
    } else if (ShiftPress(SDLK_LEFT)) {
        MoveCarets(active.view, DIR_LEFT, false, SHIFT_PRESS);
    } else if (AltPress(SDLK_LEFT)) {
        NextActiveWindowID = SwitchWindow(DIR_LEFT)->id;
    } else if (Press(SDLK_LEFT)) {
        MoveCarets(active.view, DIR_LEFT);
    }

    if (CtrlShiftPress(SDLK_RIGHT)) {
        MoveCarets(active.view, DIR_RIGHT, CTRL_PRESSED, SHIFT_PRESS);
    } else if (CtrlPress(SDLK_RIGHT)) {
        MoveCarets(active.view, DIR_RIGHT, CTRL_PRESSED);
    } else if (ShiftPress(SDLK_RIGHT)) {
        MoveCarets(active.view, DIR_RIGHT, false, SHIFT_PRESS);
    } else if (AltPress(SDLK_RIGHT)) {
        NextActiveWindowID = SwitchWindow(DIR_RIGHT)->id;
    } else if (Press(SDLK_RIGHT)) {
        MoveCarets(active.view, DIR_RIGHT);
    }

    if (CtrlShiftPress(SDLK_Z)) {
        RedoEdit(active.buffer, &active.view->carets);
    } else if (CtrlPress(SDLK_Z)) {
        UndoEdit(active.buffer, &active.view->carets);
    }

    if (CtrlPress(SDLK_C)) {
        ClipboardCopy(active.view);
    } else if (CtrlPress(SDLK_V)) {
        ClipboardPaste(active.view);
    } else if (CtrlPress(SDLK_X)) {
        SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
        ClipboardCopy(active.view);
        Replace(active.view, u"");
    }

    if (CtrlPress(SDLK_A)) {
        SelectEntireBuffer(active.view);
        active.view->update_scroll = false;
    }

    if (ShiftPress(SDLK_PAGEUP)) {
        CheckpointBeforeGoto(active.window);
        MoveCursorByPageSize(active.window, DIR_UP, SHIFT_PRESS);
    } else if (CtrlPress(SDLK_PAGEUP)) {
        CheckpointBeforeGoto(active.window);
        SelectRange(active.view, MakeRange(0));
    } else if (Press(SDLK_PAGEUP)) {
        CheckpointBeforeGoto(active.window);
        MoveCursorByPageSize(active.window, DIR_UP);
    }

    if (ShiftPress(SDLK_PAGEDOWN)) {
        CheckpointBeforeGoto(active.window);
        MoveCursorByPageSize(active.window, DIR_DOWN, SHIFT_PRESS);
    } else if (CtrlPress(SDLK_PAGEDOWN)) {
        CheckpointBeforeGoto(active.window);
        SelectRange(active.view, MakeRange(active.buffer->len));
    }  else if (Press(SDLK_PAGEDOWN)) {
        CheckpointBeforeGoto(active.window);
        MoveCursorByPageSize(active.window, DIR_DOWN);
    }

    if (ShiftPress(SDLK_HOME)) {
        CheckpointBeforeGoto(active.window);
        MoveCursorToSide(active.view, DIR_LEFT, SHIFT_PRESS);
    } else if (Press(SDLK_HOME)) {
        CheckpointBeforeGoto(active.window);
        MoveCursorToSide(active.view, DIR_LEFT);
    }

    if (ShiftPress(SDLK_END)) {
        CheckpointBeforeGoto(active.window);
        MoveCursorToSide(active.view, DIR_RIGHT, SHIFT_PRESS);
    } else if (Press(SDLK_END)) {
        CheckpointBeforeGoto(active.window);
        MoveCursorToSide(active.view, DIR_RIGHT);
    }

    if (CtrlShiftPress(SDLK_TAB)) {
    } else if (ShiftPress(SDLK_TAB)) {
        IndentSelectedLines(active.view, SHIFT_PRESS);
    } else if (CtrlPress(SDLK_TAB)) {
    } else if (Press(SDLK_TAB)) {
        IndentSelectedLines(active.view);
    }

    if (CtrlPress(SDLK_LEFTBRACKET)) {
        IndentSelectedLines(active.view, SHIFT_PRESS);
    }
    if (CtrlPress(SDLK_RIGHTBRACKET)) {
        IndentSelectedLines(active.view);
    }

    if (CtrlShiftPress(SDLK_K)) {
        KillSelectedLines(active.view);
    }

    if (CtrlPress(SDLK_BACKSPACE)) {
        Delete(active.view, DIR_LEFT, CTRL_PRESSED);
    } else if (Press(SDLK_BACKSPACE)) {
        Delete(active.view, DIR_LEFT);
    }

    if (CtrlPress(SDLK_DELETE)) {
        Delete(active.view, DIR_RIGHT, CTRL_PRESSED);
    } else if (Press(SDLK_DELETE)) {
        Delete(active.view, DIR_RIGHT);
    }

    if (event.kind == EVENT_TEXT_INPUT) {
        Scratch  scratch;
        String   string = event.text;
        String16 string16 = ToString16(scratch, string);
        Replace(active.view, string16);
    }

    if (CtrlPress(SDLK_D)) {
        CheckpointBeforeGoto(active.window);
        String16 string = GetString(active.buffer, active.view->carets[0].range);
        Caret    caret  = FindNext(active.buffer, string, active.view->carets[0]);
        Insert(&active.view->carets, caret, 0);
        MergeCarets(active.buffer, &active.view->carets);
    }

    if (CtrlPress(SDLK_EQUALS)) {
        StyleFontSize += 1;
        ReloadFont(StyleFont, (U32)StyleFontSize);
    }
    if (CtrlPress(SDLK_MINUS)) {
        if (StyleFontSize > 4) {
            StyleFontSize -= 1;
            ReloadFont(StyleFont, (U32)StyleFontSize);
        }
    }

    if (CtrlPress(SDLK_E)) {
    } else if (AltPress(SDLK_E)) {
    }

    if (CtrlShiftPress(SDLK_RETURN)) {
        MoveCursorToSide(active.view, DIR_LEFT);
        IdentedNewLine(active.view);
        MoveCarets(active.view, DIR_UP);
    } else if (CtrlPress(SDLK_RETURN)) {
        MoveCursorToSide(active.view, DIR_RIGHT);
        IdentedNewLine(active.view);
    } else if (Press(SDLK_RETURN)) {
        IdentedNewLine(active.view);
    }


    if (active.view->fuzzy_search) {
        if (!ProcessIsActive(active.view->id)) {
            Scratch          scratch;
            String16         last_line_string = GetLineStringWithoutNL(active.buffer, active.buffer->line_starts.len - 1);
            if (active.view->prev_search_line != last_line_string) {
                active.view->prev_search_line = last_line_string;
                Array<FuzzyPair> ratings = FuzzySearchLines(scratch, active.buffer, 0, active.buffer->line_starts.len - 1, last_line_string);

                Buffer *temp_buffer = CreateTempBuffer(scratch, active.buffer->cap);
                For(IterateInReverse(&ratings)) {
                    String16 s = GetLineStringWithoutNL(active.buffer, it.index);
                    if (s.len == 0) continue;
                    RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), s);
                    RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), u"\n");
                }
                RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), last_line_string);

                Caret caret = active.view->carets[0];
                SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
                SelectEntireBuffer(active.view);
                Replace(active.view, GetString(temp_buffer));
                active.view->carets[0] = caret;
            }
        }
    }

    if (CtrlPress(SDLK_F)) {
        Window *window = GetWindow(SearchBarWindowID);
        window->visible = !window->visible;
    }

    if (CtrlPress(SDLK_S)) {
        SaveBuffer(active.buffer);
    }

    if (CtrlPress(SDLK_PERIOD)) {
        String name = ChopLastSlash(main.buffer->name);
        if (EndsWith(main.buffer->name, "dirlisting")) {
            name = ChopLastSlash(name);
        }
        Open(name);
    }

    if (CtrlShiftPress(SDLK_L)) {
        EncloseSpace(active.view);
    } else if (CtrlPress(SDLK_L)) {
        EncloseLine(active.view);
    }

    if (CtrlShiftPress(SDLK_G)) {
    } else if (CtrlPress(SDLK_G)) {

    }

    if (AltPress(SDLK_Q)) {
        GotoBackward(main.window);
    }


    if (CtrlPress(SDLK_Q)) {
        if (active.view->fuzzy_search) {
            FuzzySearchOpen(active);
        } else {
            Open(FetchLoadWord());
        }
    }

    if (Press(SDLK_ESCAPE)) {
        active.view->carets.len = 1;
        active.view->carets[0] = MakeCaret(GetFront(active.view->carets[0]));

        if (active.window->lose_focus_on_escape && active.window->id == ActiveWindowID) {
            if (active.window->layout) {
                //
            } else {
                NextActiveWindowID = LastActiveLayoutWindowID;
            }
        }
    }

    // :OnCommandEnding
    MergeCarets(active.buffer, &active.view->carets);
    IF_DEBUG(AssertRanges(active.view->carets));
}
