From 641c20b22da24411e76fe102abc33ffa291d93fd Mon Sep 17 00:00:00 2001 From: Haydar Metin Date: Wed, 28 Feb 2024 11:11:09 +0100 Subject: [PATCH] Improve code --- package.json | 3 +- src/common/typescript.ts | 1 + src/webview/components/memory-table.tsx | 114 +++++++++++------------- src/webview/utils/window.ts | 22 +++++ 4 files changed, 77 insertions(+), 63 deletions(-) create mode 100644 src/webview/utils/window.ts diff --git a/package.json b/package.json index 8f0d247..46d5daa 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "@vscode/codicons": "^0.0.32", "fast-deep-equal": "^3.1.3", "formik": "^2.4.5", + "lodash": "^4.17.21", "memoize-one": "^6.0.0", "primeflex": "^3.3.1", "primereact": "^10.3.1", @@ -251,4 +252,4 @@ "extensionKind": [ "ui" ] -} \ No newline at end of file +} diff --git a/src/common/typescript.ts b/src/common/typescript.ts index 910d0d8..b00a1d8 100644 --- a/src/common/typescript.ts +++ b/src/common/typescript.ts @@ -16,6 +16,7 @@ export type RequiredKey = T & { [P in K]-?: T[P] }; +// https://stackoverflow.com/a/8511350 export function isObject(arg: unknown): arg is object { return typeof arg === 'object' && !Array.isArray(arg) && diff --git a/src/webview/components/memory-table.tsx b/src/webview/components/memory-table.tsx index 3a2276e..58c3345 100644 --- a/src/webview/components/memory-table.tsx +++ b/src/webview/components/memory-table.tsx @@ -21,21 +21,30 @@ import { DataTable, DataTableCellSelection, DataTableProps, DataTableRowData, Da import { ProgressSpinner } from 'primereact/progressspinner'; import React from 'react'; import { TableRenderOptions } from '../columns/column-contribution-service'; -import { Decoration, Memory, MemoryDisplayConfiguration, MemoryState, ScrollingBehavior, isTrigger } from '../utils/view-types'; +import { Decoration, Memory, MemoryDisplayConfiguration, MemoryState, isTrigger } from '../utils/view-types'; import isDeepEqual from 'fast-deep-equal'; import { AddressColumn } from '../columns/address-column'; import { classNames } from 'primereact/utils'; +import { approximateNumberOfFittingElements } from '../utils/window'; export interface MoreMemorySelectProps { activeReadArguments: Required; options: number[]; direction: 'above' | 'below'; - scrollingBehavior: ScrollingBehavior; fetchMemory(partialOptions?: Partial): Promise; } -export const MoreMemorySelect: React.FC = ({ activeReadArguments, options, fetchMemory, direction, scrollingBehavior }) => { - const [numBytes, setNumBytes] = React.useState(options[0]); +export interface MoreMemoryAboveSelectProps extends MoreMemorySelectProps { + direction: 'above'; + shouldPrepend?: boolean; +} + +export interface MoreMemoryBelowSelectProps extends MoreMemorySelectProps { + direction: 'below'; +} + +export const MoreMemorySelect: React.FC = props => { + const [numBytes, setNumBytes] = React.useState(props.options[0]); const containerRef = React.createRef(); const onSelectChange = (e: React.ChangeEvent): void => { e.stopPropagation(); @@ -46,43 +55,33 @@ export const MoreMemorySelect: React.FC = ({ activeReadAr const updateMemory = (e: React.MouseEvent | React.KeyboardEvent): void => { containerRef.current?.blur(); if (isTrigger(e)) { - let request: Partial | undefined; + const direction = props.direction; - if (scrollingBehavior === 'Paginate') { - request = createPaginateRequest(activeReadArguments); - } else if (scrollingBehavior === 'Auto-Append') { - request = createAutoAppendRequest(activeReadArguments); + if (direction === 'above') { + handleAboveDirection(props); + } else if (direction === 'below') { + handleBelowDirection(props); } else { - throw new Error(`${scrollingBehavior} is not supported. Did you define a fetch method for it?`); + throw new Error(`Unknown direction ${direction}`); } - - fetchMemory(request); } }; - const createPaginateRequest = (arg: Required): Partial => { - let newOffset = arg.offset; - if (direction === 'above') { - newOffset = arg.offset - numBytes; - } - if (direction === 'below') { - newOffset = arg.offset + numBytes; - } + const handleAboveDirection = (aboveProps: MoreMemoryAboveSelectProps): void => { + const { activeReadArguments, shouldPrepend, fetchMemory } = aboveProps; - return { offset: newOffset }; - }; + const newOffset = activeReadArguments.offset - numBytes; + const newCount = shouldPrepend ? activeReadArguments.count + numBytes : activeReadArguments.count; - const createAutoAppendRequest = (arg: Required): Partial => { - let newOffset = arg.offset; - let newCount = arg.offset; + fetchMemory({ offset: newOffset, count: newCount }); + }; - if (direction === 'above') { - newOffset = arg.offset - numBytes; - } + const handleBelowDirection = (belowProps: MoreMemoryBelowSelectProps): void => { + const { activeReadArguments, fetchMemory } = belowProps; - newCount = arg.count + numBytes; + const newOffset = activeReadArguments.offset + numBytes; - return { offset: newOffset, count: newCount }; + fetchMemory({ offset: newOffset }); }; return ( @@ -101,7 +100,7 @@ export const MoreMemorySelect: React.FC = ({ activeReadAr onChange={onSelectChange} tabIndex={0} > - {options.map(option => ( + {props.options.map(option => ( ))} - {`more bytes ${direction}`} + {`more bytes ${props.direction}`} ); @@ -165,21 +164,6 @@ export class MemoryTable extends React.PureComponent): void { - if (!MemoryState.hasMemory(prevProps) || !MemoryState.hasMemory(this.props)) { - return; - } - - const hasMemoryChanged = prevProps.memory?.address !== this.props.memory?.address + const hasMemoryChanged = (!MemoryState.hasMemory(prevProps) || !MemoryState.hasMemory(this.props)) + || prevProps.memory.address !== this.props.memory.address || prevProps.activeReadArguments.offset !== this.props.activeReadArguments.offset || prevProps.activeReadArguments.count !== this.props.activeReadArguments.count; @@ -225,7 +206,7 @@ export class MemoryTable extends React.PureComponent ({ ...prev, selection: null })); } - if (this.props.scrollingBehavior === 'Auto-Append') { + if (MemoryState.hasMemory(prevProps) && MemoryState.hasMemory(this.props) && this.props.scrollingBehavior === 'Auto-Append') { this.ensureSufficientVisibleRowsForScrollbar(); // We have now less count than before - there was a change from outside @@ -339,7 +320,7 @@ export class MemoryTable extends React.PureComponent ; @@ -397,7 +378,6 @@ export class MemoryTable extends React.PureComponent ; @@ -460,15 +440,25 @@ export namespace MemoryTable { export const GROUP_SEPARATOR = 'group-separator'; /** - * Approximates how many table rows visually fit into the given container without scrolling + * Approximates how many rows visually fit into the given wrapper without scrolling */ - export function approximateNumberOfFittingRows(container: HTMLElement): number { - const row = container.querySelector('tbody > tr'); + export function visibleRowsInWrapperCount(wrapper?: HTMLElement): number { + if (wrapper) { + const row = wrapper.querySelector('tr'); - if (row) { - return Math.ceil(container.clientHeight / row.clientHeight); + if (row) { + return approximateNumberOfFittingElements(wrapper, row); + } } return 1; } + + /** + * Returns the number of rows that the wrapper can render at once + */ + export function renderableRowsAtOnceForWrapperCount(wrapper?: HTMLElement): number { + const buffer = 8; + return visibleRowsInWrapperCount(wrapper) + buffer; + } } diff --git a/src/webview/utils/window.ts b/src/webview/utils/window.ts new file mode 100644 index 0000000..6b311ae --- /dev/null +++ b/src/webview/utils/window.ts @@ -0,0 +1,22 @@ +/******************************************************************************** + * Copyright (C) 2024 EclipseSource and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ + +/** + * Approximates how many elements visually fit into the given container without scrolling + */ +export function approximateNumberOfFittingElements(container: HTMLElement, element: HTMLElement): number { + return Math.ceil(container.clientHeight / element.clientHeight); +}