Skip to content

Commit

Permalink
Improve code
Browse files Browse the repository at this point in the history
  • Loading branch information
haydar-metin committed Feb 28, 2024
1 parent 2e681c2 commit 641c20b
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 63 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -251,4 +252,4 @@
"extensionKind": [
"ui"
]
}
}
1 change: 1 addition & 0 deletions src/common/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

export type RequiredKey<T, K extends keyof T> = 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) &&
Expand Down
114 changes: 52 additions & 62 deletions src/webview/components/memory-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<DebugProtocol.ReadMemoryArguments>;
options: number[];
direction: 'above' | 'below';
scrollingBehavior: ScrollingBehavior;
fetchMemory(partialOptions?: Partial<DebugProtocol.ReadMemoryArguments>): Promise<void>;
}

export const MoreMemorySelect: React.FC<MoreMemorySelectProps> = ({ activeReadArguments, options, fetchMemory, direction, scrollingBehavior }) => {
const [numBytes, setNumBytes] = React.useState<number>(options[0]);
export interface MoreMemoryAboveSelectProps extends MoreMemorySelectProps {
direction: 'above';
shouldPrepend?: boolean;
}

export interface MoreMemoryBelowSelectProps extends MoreMemorySelectProps {
direction: 'below';
}

export const MoreMemorySelect: React.FC<MoreMemoryAboveSelectProps | MoreMemoryBelowSelectProps> = props => {
const [numBytes, setNumBytes] = React.useState<number>(props.options[0]);
const containerRef = React.createRef<HTMLDivElement>();
const onSelectChange = (e: React.ChangeEvent<HTMLSelectElement>): void => {
e.stopPropagation();
Expand All @@ -46,43 +55,33 @@ export const MoreMemorySelect: React.FC<MoreMemorySelectProps> = ({ activeReadAr
const updateMemory = (e: React.MouseEvent | React.KeyboardEvent): void => {
containerRef.current?.blur();
if (isTrigger(e)) {
let request: Partial<DebugProtocol.ReadMemoryArguments> | 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<DebugProtocol.ReadMemoryArguments>): Partial<DebugProtocol.ReadMemoryArguments> => {
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<DebugProtocol.ReadMemoryArguments>): Partial<DebugProtocol.ReadMemoryArguments> => {
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 (
Expand All @@ -101,15 +100,15 @@ export const MoreMemorySelect: React.FC<MoreMemorySelectProps> = ({ activeReadAr
onChange={onSelectChange}
tabIndex={0}
>
{options.map(option => (
{props.options.map(option => (
<option
key={`more-memory-select-${option}`}
value={option}
>
{option}
</option>))}
</select>
{`more bytes ${direction}`}
{`more bytes ${props.direction}`}
</div>
</div>
);
Expand Down Expand Up @@ -165,21 +164,6 @@ export class MemoryTable extends React.PureComponent<MemoryTableProps, MemoryTab
return this.props.isMemoryFetching;
}

protected get visibleRowsInDatableCount(): number {
const wrapper = this.datatableWrapper;

if (wrapper) {
return MemoryTable.approximateNumberOfFittingRows(wrapper);
}

return 1;
}

protected get appendMoreMemoryRowsCount(): number {
const buffer = 8;
return this.visibleRowsInDatableCount + buffer;
}

constructor(props: MemoryTableProps) {
super(props);

Expand Down Expand Up @@ -208,11 +192,8 @@ export class MemoryTable extends React.PureComponent<MemoryTableProps, MemoryTab
}

componentDidUpdate(prevProps: Readonly<MemoryTableProps>): 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;

Expand All @@ -225,7 +206,7 @@ export class MemoryTable extends React.PureComponent<MemoryTableProps, MemoryTab
this.setState(prev => ({ ...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
Expand Down Expand Up @@ -339,7 +320,7 @@ export class MemoryTable extends React.PureComponent<MemoryTableProps, MemoryTab
}

const datatableValues = this.datatableRef.current?.props.value;
if (datatableValues && datatableValues.length < this.appendMoreMemoryRowsCount) {
if (datatableValues && datatableValues.length < MemoryTable.renderableRowsAtOnceForWrapperCount(this.datatableWrapper)) {
// We have too few rows, we need to load more data
this.appendMoreMemory();
}
Expand All @@ -348,7 +329,7 @@ export class MemoryTable extends React.PureComponent<MemoryTableProps, MemoryTab
protected appendMoreMemory(): void {
if (!this.isLoading && MemoryState.hasMemory(this.props)) {
const options = this.createMemoryRowListOptions(this.props.memory, this.props);
const newCount = this.props.activeReadArguments.count + options.wordsPerRow * this.appendMoreMemoryRowsCount;
const newCount = this.props.activeReadArguments.count + options.wordsPerRow * MemoryTable.renderableRowsAtOnceForWrapperCount(this.datatableWrapper);
this.props.fetchMemory({ count: newCount });
}
}
Expand All @@ -367,7 +348,7 @@ export class MemoryTable extends React.PureComponent<MemoryTableProps, MemoryTab
activeReadArguments={this.props.activeReadArguments}
options={[128, 256, 512]}
direction='above'
scrollingBehavior={this.props.scrollingBehavior}
shouldPrepend={this.props.scrollingBehavior === 'Auto-Append'}
fetchMemory={this.props.fetchMemory}
/>
</div>;
Expand Down Expand Up @@ -397,7 +378,6 @@ export class MemoryTable extends React.PureComponent<MemoryTableProps, MemoryTab
activeReadArguments={this.props.activeReadArguments}
options={[128, 256, 512]}
direction='below'
scrollingBehavior={this.props.scrollingBehavior}
fetchMemory={this.props.fetchMemory}
/>
</div>;
Expand Down Expand Up @@ -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<HTMLTableRowElement>('tbody > tr');
export function visibleRowsInWrapperCount(wrapper?: HTMLElement): number {
if (wrapper) {
const row = wrapper.querySelector<HTMLElement>('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;
}
}
22 changes: 22 additions & 0 deletions src/webview/utils/window.ts
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit 641c20b

Please sign in to comment.