diff --git a/ViewModels/GridViewModel.fs b/ViewModels/GridViewModel.fs index 7d0cf76..c22b53a 100644 --- a/ViewModels/GridViewModel.fs +++ b/ViewModels/GridViewModel.fs @@ -24,6 +24,12 @@ module private GridViewModelHelper = open GridViewModelHelper +type TrackedGridPosition = + { + mutable trow: int + mutable tcol: int + } + [] type GridDrawOperation = | Scroll of int * int * int * int * int * int @@ -214,7 +220,7 @@ and GridViewModel(_gridid: int, ?_parent: GridViewModel, ?_gridsize: GridSize) a #endif clearBuffer preserveContent - let putBuffer (M: ReadOnlyMemory<_>) = + let putBuffer (M: ReadOnlyMemory) = //if _gridid = 1 then // trace _gridid "putBuffer" for line in M.Span do @@ -228,22 +234,36 @@ and GridViewModel(_gridid: int, ?_parent: GridViewModel, ?_gridsize: GridSize) a for _i = 1 to rep do m_gridbuffer.[row, col].hlid <- hlid m_gridbuffer.[row, col].text <- cell.text + for m in m_gridbuffer.[row, col].marks do + m_extmarks.Remove m.mark |> ignore + m_gridbuffer.[row, col].marks <- [] col <- col + 1 markDirty { row = row; col = line.col_start; height = 1; width = col - line.col_start } + let clearMarks() = + for _,cell,_ in m_extmarks.Values do + cell.marks <- [] + m_extmarks.Clear() + #if DEBUG + trace _gridid $"clearMarks" + #endif + let putExtmarks (M: Extmark[]) = + #if DEBUG + trace _gridid $"putExtmarks:\n%A{M}" + #endif let rec rm (l: Extmark list) (id: int) = match l with | [] -> [] | {mark = mark} :: rest when mark = id -> rm rest id | x :: rest -> x :: (rm rest id) for mark in M do - let { mark = id; startRow = row; col = col } = mark + let { mark = id; row = row; col = col } = mark match m_extmarks.TryGetValue id with - | true, (mark, cell, r, c) -> + | true, (_, cell, _) -> cell.marks <- rm cell.marks id | _ -> () - m_extmarks.[id] <- (mark, m_gridbuffer.[row, col], row, col) + m_extmarks.[id] <- (mark, m_gridbuffer.[row, col], { trow = row; tcol = col }) m_gridbuffer.[row, col].marks <- mark :: m_gridbuffer.[row, col].marks let changeMode (name: string) (index: int) = @@ -299,9 +319,23 @@ and GridViewModel(_gridid: int, ?_parent: GridViewModel, ?_gridsize: GridSize) a trace _gridid "scroll: %A %A %A %A %A %A" top bot left right rows cols #endif + // copies the line from src to dst, and then refill the dst with "new cells" let copy src dst = if src >= 0 && src < m_gridsize.rows && dst >= 0 && dst < m_gridsize.rows then - GridBufferCell.MoveLine m_gridbuffer src dst left right + for c = left to right - 1 do + // since the "dst" line will be overwritten, we may say it's really new cells... + let dst_cell = m_gridbuffer.[dst,c] + let src_cell = m_gridbuffer.[src,c] + m_gridbuffer.[dst,c] <- src_cell + m_gridbuffer.[src,c] <- dst_cell + // update src row marks -> dst row + for m in src_cell.marks do + let _,_,pos = m_extmarks.[m.mark] + pos.trow <- dst + // remove dst row marks + for m in dst_cell.marks do + m_extmarks.Remove m.mark |> ignore + dst_cell.marks <- [] if rows > 0 then for i = top + rows to bot do @@ -426,6 +460,7 @@ and GridViewModel(_gridid: int, ?_parent: GridViewModel, ?_gridsize: GridSize) a | WinExternalPos(_,win) -> setWinExternalPos win | WinViewport(id, win, top, bot, row, col, lc) -> setWinViewport win top bot row col lc | WinExtmarks(win, marks) -> if win = m_winhnd then putExtmarks marks + | WinExtmarksClear(win) -> if win = m_winhnd then clearMarks() | x -> trace _gridid "unimplemented command: %A" x let fontConfig() = @@ -748,7 +783,7 @@ and GridViewModel(_gridid: int, ?_parent: GridViewModel, ?_gridsize: GridSize) a member __.FindTargetWidget (r: int) (c: int) = let placements = getGuiWidgetPlacements m_bufnr m_extmarks.Values - |> Seq.tryPick(fun ({ns = ns; mark = mark},cell,cr,cc) -> + |> Seq.tryPick(fun ({ns = ns; mark = mark},cell,{trow=cr;tcol=cc}) -> if ns <> guiwidgetNamespace || not(cell.ContainsMark mark) then None else match placements.TryGetValue mark with | false, _ -> None diff --git a/Views/Grid.xaml.fs b/Views/Grid.xaml.fs index 531812b..481bdc9 100644 --- a/Views/Grid.xaml.fs +++ b/Views/Grid.xaml.fs @@ -354,11 +354,12 @@ type Grid() as this = let view_top,view_bot,cur_row,line_count = let top,bot,row,_,lc = vm.ScrollbarData float top, float bot, float row, float lc + use _mainClipclip = ctx.PushClip(Rect(vm_x, vm_y, vm_w, vm_h)) // gui widgets do let placements = getGuiWidgetPlacements vm.BufNr - for ({ns = ns; mark = mark}, cell, r, c) in vm.Extmarks.Values do + for ({ns = ns; mark = mark}, cell, {trow=r;tcol=c}) in vm.Extmarks.Values do // if cell.marks does not have this mark, it means cell has scrolled out of view. if ns = guiwidgetNamespace && cell.ContainsMark mark then match (placements.TryGetValue mark) with diff --git a/def.fs b/def.fs index e3ec3b0..87b98d6 100644 --- a/def.fs +++ b/def.fs @@ -304,8 +304,7 @@ type Extmark = { ns: int mark: int - startRow: int - endRow: int + row: int col: int } @@ -369,6 +368,7 @@ type RedrawCommand = /// watch for a specific namespace `ns_id`. `start_row`, `end_row` and /// `start_col` are relative to the window. | WinExtmarks of win: int * marks: Extmark[] +| WinExtmarksClear of win: int /// Display messages on `grid`. The grid will be displayed at `row` on the /// default grid (grid=1), covering the full column width. `scrolled` /// indicates whether the message area has been scrolled to cover other @@ -673,18 +673,18 @@ let parse_int_singleton = -> Some(i) | _ -> None -let parse_extmark = - function - | ObjArray [| Integer32 a; Integer32 b; Integer32 c; Integer32 d; Integer32 e |] - -> Some({ns = a; mark = b; startRow = c; endRow = d; col = e}) - | _ -> None - -let parse_win_extmarks = +let parse_win_extmarks_1 = function - | ObjArray [| (Integer32 win); ObjArray(PX(parse_extmark)data) |] - -> Some(WinExtmarks(win, data)) + | ObjArray [| Integer32 a; Integer32 b; Integer32 c; Integer32 d; Integer32 e |] + -> Some(a,{ns=b;mark=c;row=d;col=e}) | _ -> None +let parse_win_extmarks_2 (tuples: (int*Extmark)[]) = + tuples + |> Array.groupBy fst + |> Array.map(fun (win, marks) -> + WinExtmarks(win, marks |> Array.map snd)) + let unwrap_multi xs = match xs with | [| one |] -> one @@ -725,7 +725,8 @@ let parse_redrawcmd (x: obj) = | C("win_scroll_over_reset", _) -> WinScrollOverReset | C("win_close", PX(parse_int_singleton)ids) -> ids |> Array.map(WinClose) |> unwrap_multi | C("win_viewport", PX(parse_win_viewport)cmds) -> unwrap_multi cmds - | C("win_extmarks", PX(parse_win_extmarks)cmds) -> unwrap_multi cmds + | C("win_extmarks", PX(parse_win_extmarks_1)cmds) -> cmds |> parse_win_extmarks_2 |> unwrap_multi + | C1("win_extmarks_clear", PX(Integer32)ids) -> ids |> Array.map(WinExtmarksClear) |> unwrap_multi | C1("msg_set_pos", [| (Integer32 grid); (Integer32 row) (Bool scrolled); (String sep_char) |]) -> MsgSetPos(grid, row,scrolled, sep_char) diff --git a/model.fs b/model.fs index 1b2de9a..f45257a 100644 --- a/model.fs +++ b/model.fs @@ -115,7 +115,8 @@ module private ModelImpl = | PopupMenuSelect _ | PopupMenuHide _ | Busy _ | Mouse _ | ModeChange _ | GridCursorGoto _ - | WinExtmarks _ -> broadcast cmd + | WinExtmarks _ + | WinExtmarksClear _ -> broadcast cmd // Unicast | GridClear id | GridScroll(id,_,_,_,_,_,_) | WinClose id | WinHide(id) diff --git a/ui.fs b/ui.fs index 00c4379..2479940 100644 --- a/ui.fs +++ b/ui.fs @@ -35,14 +35,6 @@ type GridBufferCell = |> List.exists (fun (x: Extmark) -> x.mark = markid) static member CreateGrid r c = Array2D.init r c (fun _ _ -> { text = Rune.empty; hlid = 0; marks = [] }) - // copies the line from src to dst, and then refill the dst with "new cells" - static member MoveLine (grid: GridBufferCell[,]) src dst left right = - for c = left to right - 1 do - // since the "dst" line will be overwritten, we may say it's really new cells... - let tmp = grid.[dst,c] - grid.[dst,c] <- grid.[src,c] - grid.[src,c] <- tmp - tmp.marks <- [] [] type GridSize =